<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>The Wagner</title><link href="https://thewagner.net/" rel="alternate"/><link href="https://thewagner.net/feeds/all.atom.xml" rel="self"/><id>https://thewagner.net/</id><updated>2025-12-31T00:00:00+01:00</updated><entry><title>Year 2025 in review</title><link href="https://thewagner.net/blog/2025/12/31/year-2025-in-review/" rel="alternate"/><published>2025-12-31T00:00:00+01:00</published><updated>2025-12-31T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2025-12-31:/blog/2025/12/31/year-2025-in-review/</id><summary type="html">&lt;p&gt;The first quarter of the year I trained again for the &lt;a href="https://training.thewagner.net/blog/2025/05/04/20-km-de-lausanne-2025/"&gt;20 km of Lausanne&lt;/a&gt;
where I beat my 2024 personal best.  In May, I joined a few friends for &lt;a href="https://training.thewagner.net/blog/2025/05/19/toscana-gravel-2025/"&gt;a week
of gravel cycling&lt;/a&gt; through the hills of&amp;nbsp;Tuscany.&lt;/p&gt;
&lt;h1&gt;Articles&lt;/h1&gt;
&lt;p&gt;In February, I described our use of the &lt;a href="https://thewagner.net/blog/2025/02/15/six-months-of-cdk/"&gt;&lt;span class="caps"&gt;AWS …&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;The first quarter of the year I trained again for the &lt;a href="https://training.thewagner.net/blog/2025/05/04/20-km-de-lausanne-2025/"&gt;20 km of Lausanne&lt;/a&gt;
where I beat my 2024 personal best.  In May, I joined a few friends for &lt;a href="https://training.thewagner.net/blog/2025/05/19/toscana-gravel-2025/"&gt;a week
of gravel cycling&lt;/a&gt; through the hills of&amp;nbsp;Tuscany.&lt;/p&gt;
&lt;h1&gt;Articles&lt;/h1&gt;
&lt;p&gt;In February, I described our use of the &lt;a href="https://thewagner.net/blog/2025/02/15/six-months-of-cdk/"&gt;&lt;span class="caps"&gt;AWS&lt;/span&gt; Cloud Development Kit&lt;/a&gt; at my
new job.  I believe I found a right length and format to explain why this tool
helps me building cloud&amp;nbsp;infrastructure.&lt;/p&gt;
&lt;p&gt;In May, I &lt;a href="https://thewagner.net/blog/2025/05/31/homelab-turns-five/"&gt;published an anniversary post for my Homelab&lt;/a&gt;.  For five
years I manage my own home infrastructure with Nix which makes me proud and&amp;nbsp;happy.&lt;/p&gt;
&lt;p&gt;In October, I analyzed &lt;a href="https://thewagner.net/blog/2025/10/11/my-note-taking-process/"&gt;my note taking progress&lt;/a&gt; and explained how a
two-step process helps me to write great notes.  I also
&lt;a href="https://thewagner.net/blog/2025/10/26/normal-accidents/"&gt;reviewed&lt;/a&gt; Charles Perrow&amp;#8217;s &lt;em&gt;Normal Accidents&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Finally, as in the past few years, in December I spent my free time solving the
&lt;a href="https://thewagner.net/blog/2025/12/12/advent-of-code-2025/"&gt;Advent of Code&lt;/a&gt;&amp;nbsp;puzzles.&lt;/p&gt;
&lt;h1&gt;Tech&lt;/h1&gt;
&lt;p&gt;I spent some time exploring the &lt;a href="https://www.nats.io"&gt;&lt;span class="caps"&gt;NATS&lt;/span&gt;&lt;/a&gt; communication
system and the &lt;a href="https://replicant.fun/"&gt;Replicant&lt;/a&gt; library for building web
applications.  I hope I&amp;#8217;ll have an opportunity to integrate them into future&amp;nbsp;projects.&lt;/p&gt;
&lt;h1&gt;Books&lt;/h1&gt;
&lt;p&gt;Many years ago a friend of mine gifted me &lt;em&gt;The Making of the Atomic Bomb&lt;/em&gt; by
Richard Rhodes.  I cannot recall why I waited so long to open it, I finally
read it this summer. In just a few days I consumed Andy Weir&amp;#8217;s &lt;em&gt;Hail Mary
Project&lt;/em&gt;. To finish the year, I spent my Christmas reading Bertrand Meyer&amp;#8217;s
&lt;em&gt;Agile!&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading my blog and happy&amp;nbsp;2026!&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Advent of Code 2025</title><link href="https://thewagner.net/blog/2025/12/12/advent-of-code-2025/" rel="alternate"/><published>2025-12-12T00:00:00+01:00</published><updated>2025-12-12T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2025-12-12:/blog/2025/12/12/advent-of-code-2025/</id><summary type="html">&lt;p&gt;Solving the Advent of Code 2025 puzzles in&amp;nbsp;Clojure.&lt;/p&gt;</summary><content type="html">&lt;p&gt;This year, &lt;a href="https://thewagner.net/blog/2024/12/25/advent-of-code-2024/"&gt;again&lt;/a&gt;, December starts with the &lt;a href="https://adventofcode.com/"&gt;Advent of
Code&lt;/a&gt; puzzles.  Eric Wastl
&lt;a href="https://www.reddit.com/r/adventofcode/comments/1ocwh04/changes_to_advent_of_code_starting_this_december/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button"&gt;announced&lt;/a&gt; that from this year the puzzle series last only 12
days instead of the 25.  In the previous years I felt exhausted by the end of
the month so I don&amp;#8217;t mind that this year ends&amp;nbsp;earlier.&lt;/p&gt;
&lt;h1&gt;Puzzles&lt;/h1&gt;
&lt;p&gt;Between December 1 and December 12, a programming puzzle appears every day on
the Advent of Code website.  Each problem has two parts, the second part
unlocks after you complete the first.  To understand each day&amp;#8217;s puzzle, go to
the website and read the full description (for example &lt;a href="https://adventofcode.com/2025/day/1"&gt;Day 1: Secret
Entrance&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: If you still plan to work on the puzzles, stop reading&amp;nbsp;now.&lt;/p&gt;
&lt;h1&gt;Highlights&lt;/h1&gt;
&lt;p&gt;For the sixth consequtive year, I write my solutions in Clojure.  Since I don&amp;#8217;t
use this language professionally, I look forward to coding in Clojure every
December.  Usually, I solved the day&amp;#8217;s problem before leaving to work, though
sometimes I polished my code in the&amp;nbsp;evening.&lt;/p&gt;
&lt;p&gt;I sought external help to solve the second parts of &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2025/day07.clj"&gt;Day 7&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2025/day10.clj"&gt;Day
10&lt;/a&gt; and I haven&amp;#8217;t yet started &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2025/day12.clj"&gt;Day 12&lt;/a&gt;.  The other days went
smoothly.  I particularly enjoyed &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2025/day06.clj"&gt;Day 6&lt;/a&gt; which required reading the
input file from right to left, to satisfy to the Elf&amp;#8217;s clumsy&amp;nbsp;specification.&lt;/p&gt;
&lt;p&gt;You can find my solutions on &lt;a href="https://github.com/wagdav/advent-of-code/aoc2025"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Acknowledgments&lt;/h1&gt;
&lt;p&gt;Thanks &lt;a href="https://twitter.com/ericwastl"&gt;Eric Wastl&lt;/a&gt; for creating and running
&lt;a href="https://adventofcode.com"&gt;Advent of Code&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Normal accidents</title><link href="https://thewagner.net/blog/2025/10/26/normal-accidents/" rel="alternate"/><published>2025-10-26T00:00:00+02:00</published><updated>2025-10-26T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2025-10-26:/blog/2025/10/26/normal-accidents/</id><summary type="html">&lt;p&gt;This summer I read &lt;em&gt;Normal Accidents&lt;/em&gt; by Charles Perrow, which analyzes
failures in the nuclear industry, petrochemical plants, planes and airways,
marine transport, and other earthbound systems like dams and mining. In the
book&amp;#8217;s title the word &amp;#8220;normal&amp;#8221; means &lt;em&gt;systemic&lt;/em&gt;, accidents that involve the
unanticipated interaction of many failures …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This summer I read &lt;em&gt;Normal Accidents&lt;/em&gt; by Charles Perrow, which analyzes
failures in the nuclear industry, petrochemical plants, planes and airways,
marine transport, and other earthbound systems like dams and mining. In the
book&amp;#8217;s title the word &amp;#8220;normal&amp;#8221; means &lt;em&gt;systemic&lt;/em&gt;, accidents that involve the
unanticipated interaction of many failures.  Perrow argues that complex and
tightly coupled systems with catastrophic potential have an &lt;em&gt;inherent&lt;/em&gt;
susceptibility to normal&amp;nbsp;accidents.&lt;/p&gt;
&lt;h1&gt;No easy&amp;nbsp;explanations&lt;/h1&gt;
&lt;p&gt;Perrow found that most accident analysis reports simplistically conclude that a
unit failure, an operator error, or poor management caused an&amp;nbsp;accident.&lt;/p&gt;
&lt;p&gt;For instance, in Chapter 6 &lt;em&gt;Marine Accidents&lt;/em&gt;, Perrow analyzes ship collisions,
a large majority of which occur in inland waters in clear weather with a pilot
on board.  Furthermore, the two ships often do not initially follow a collision
course; instead, one or both change course after becoming aware of the other in
a manner that effects a collision.  The crews had years of experience, the
ships had all systems operational and neither ship intended to crash into the&amp;nbsp;other.&lt;/p&gt;
&lt;p&gt;Marine transport, including the ships, their crew and all the built-in safety
devices form a complex system where interactions may occur in an unexpected&amp;nbsp;sequence.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure1" src="https://thewagner.net/images/normal-accidents-perception.svg"&gt;&lt;/p&gt;
&lt;p&gt;We reason about the behavior of a complex system via our own mental model.  We
use this model to draw conclusions about interactions which we cannot directly
see.  This helps us tremendously in finding problems when things go wrong.  On
the contrary, we may also reject signals from the system that contradict our
own model of the&amp;nbsp;world.&lt;/p&gt;
&lt;p&gt;Instead of blaming a single component or a person, Perrow develops his &lt;span class="caps"&gt;DEPOSE&lt;/span&gt;
framework which considers the Design, Equipment, Procedures, Operators,
Supplies and materials, and the Environment of a system.  The interactions
among these aspects determine how a system behaves and how it&amp;nbsp;fails.&lt;/p&gt;
&lt;h1&gt;System, subsystem, units and&amp;nbsp;parts&lt;/h1&gt;
&lt;p&gt;Perrow uses a four-level hierarchical system model composed of parts, units,
subsystems, and the full system.  For example, a nuclear power plant as the
system comprises a cooling subsystem which contains a steam generator unit with
many parts like pumps, motors and&amp;nbsp;piping.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure2" src="https://thewagner.net/images/system-levels.svg" title="Hierarchical system of subsystems, units and parts"&gt;&lt;/p&gt;
&lt;p&gt;I highlighted a unit that belongs to two subsystems, often called a
&amp;#8220;common-mode unit&amp;#8221;.  For example, if two subsystems use a single electricity
source, a power outage may immediately disrupt both.  Most systems contain such
units, often for economic or efficiency&amp;nbsp;reasons.&lt;/p&gt;
&lt;p&gt;Most systems include safety features, often implemented as extra parts and
units. Paradoxically, the addition of more safety mechanisms often increases
the possibility of unanticipated interactions with existing&amp;nbsp;components.&lt;/p&gt;
&lt;h1&gt;Interaction and&amp;nbsp;Coupling&lt;/h1&gt;
&lt;p&gt;I reproduced Figure 3.1 (and later repeated as Figure 9.1) from the book, which
organizes human and technological systems by the nature of interaction and&amp;nbsp;coupling.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure3" src="https://thewagner.net/images/interaction-coupling.svg" title="Reproduction of the interaction/coupling chart (Figures 3.1 and            9.1)"&gt;&lt;/p&gt;
&lt;p&gt;A system does useful work because its components interact with each other.
Valves open and close to control the coolant&amp;#8217;s flow.  Public officials exchange
ideas and documents in a government agency.  A conveyor belt moves the car to
the next assembly phase.  By the nature of interaction Perrow arranges systems
from &lt;em&gt;linear&lt;/em&gt; to &lt;em&gt;complex&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Perrow defines linear interactions as those that occur in some expected
sequence.  People can see and understand the cause and effect relationships in
such interactions, even when they fail.  As shown in the figure above, linear
interactions dominate assembly-line production.  In a car factory, when a
workstation on a line malfunctions, parts pile up &lt;em&gt;before&lt;/em&gt; failure point, but
stations &lt;em&gt;after&lt;/em&gt; keep working until they don&amp;#8217;t receive new pieces anymore.
Furthermore, a failure on one assembly line typically doesn&amp;#8217;t affect
neighbouring lines, at least not&amp;nbsp;immediately.&lt;/p&gt;
&lt;p&gt;On the right-hand side of the diagram we find complex systems with many hidden,
hard-to-understand interaction patterns.  Perrow spends an entire chapter on
describing the &lt;a href="https://en.wikipedia.org/wiki/Three_Mile_Island_accident"&gt;Three Mile Island&lt;/a&gt; accident.  He argues that operators
couldn&amp;#8217;t have possibly made better decisions during the accident because of the
inherent complexity of a nuclear&amp;nbsp;plant.&lt;/p&gt;
&lt;p&gt;The vertical axis of the figure represents coupling.  Tightly coupled systems
have more time-dependent processes: they cannot wait or stand by until attended
to.  We cannot change resource quantities and qualities, we cannot easily
substitute supplies, equipment or personnel.  We cannot switch the order
operations because often we only have one way to reach the production&amp;nbsp;goal.&lt;/p&gt;
&lt;p&gt;Perrow also applies his analysis to sociological systems like schools and R&amp;amp;D
firms. For example, a junior college highly regulates the sequences of classes
while at a university, students have more liberty to complete their required
credits.  By the book&amp;#8217;s definition, this makes a junior college more tightly
coupled than a university.  A university doesn&amp;#8217;t just teach, but also organizes
research, collaboration with industry often involving politics.  This makes a
university, as a system, more complex than a junior&amp;nbsp;college.&lt;/p&gt;
&lt;h1&gt;Fixing complex, tightly coupled&amp;nbsp;systems&lt;/h1&gt;
&lt;p&gt;According to Perrow&amp;#8217;s thesis, normal accidents occur in tightly coupled systems
with complex interactions.  Reducing either complexity or coupling would make
such systems safer, but often the laws of nature prevent such changes.  Most
physical and chemical reactions only occur under specific conditions, requiring
us to build control and safety systems around&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;If we cannot change a complex, tightly coupled technology — and we don&amp;#8217;t want
to abandon it —, perhaps we could prepare ourselves better to face unforeseen&amp;nbsp;events.&lt;/p&gt;
&lt;p&gt;In linear systems, where the unforeseen rarely occurs, designers rely on
standards and regulations, operators complete training sessions to handle not
only everyday operation but also failures.  In other words, linear systems
favor&amp;nbsp;centralization.&lt;/p&gt;
&lt;p&gt;Centralization also has beneficial effects on tightly coupled systems.  With
little buffer time, when a failure occurs the operator has no time to analyze
the situation.  Following a standard recovery procedure stops the failure from
propagating to other parts of the system, and helps recovering normal&amp;nbsp;operations.&lt;/p&gt;
&lt;p&gt;Tightly coupled, complex systems pose incompatible demands during incidents.
While tight coupling imposes unquestioned obedience and fast response from
operators, the complex and incomprehensible nature of interactions requires a
slow search from subsystem to subsystem to even recognize an ongoing&amp;nbsp;incident.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Perrow wrote this book in 1984, inspired by the Three Mile Island accident five
years earlier.  The 1999 edition&amp;#8217;s afterword contains a few extra references to
books and papers that further developed Perrow&amp;#8217;s ideas, now forming what we
call Normal Accident Theory.  He also added a few speculative sections about
the risks associated with growing number of interconnected computer systems.
Now we know that &lt;a href="https://en.wikipedia.org/wiki/Year_2000_problem"&gt;&lt;span class="caps"&gt;Y2K&lt;/span&gt;&lt;/a&gt; problem didn&amp;#8217;t induce an apocalypse, but we
definitely saw defective software causing&amp;nbsp;catastrophes.&lt;/p&gt;
&lt;p&gt;Though &lt;em&gt;Normal Accidents&lt;/em&gt; contains many stories where technology went horribly
wrong, Perrow puts humans at the center because we ultimately make the choices
that help or harm others and the&amp;nbsp;environment.&lt;/p&gt;
&lt;h1&gt;Acknowledgement&lt;/h1&gt;
&lt;p&gt;Thanks Rafał for suggesting and lending me this&amp;nbsp;book.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>My note-taking process</title><link href="https://thewagner.net/blog/2025/10/11/my-note-taking-process/" rel="alternate"/><published>2025-10-11T00:00:00+02:00</published><updated>2025-10-11T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2025-10-11:/blog/2025/10/11/my-note-taking-process/</id><summary type="html">&lt;p&gt;I began taking notes around age ten in primary school.  Though my teachers
certainly instructed us to do so, I don&amp;#8217;t remember if anyone actually taught me
&lt;em&gt;how&lt;/em&gt; to take notes.  Like the rest of the class, I studied and revised using
them.  I followed the teacher&amp;#8217;s explanations …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I began taking notes around age ten in primary school.  Though my teachers
certainly instructed us to do so, I don&amp;#8217;t remember if anyone actually taught me
&lt;em&gt;how&lt;/em&gt; to take notes.  Like the rest of the class, I studied and revised using
them.  I followed the teacher&amp;#8217;s explanations with a pen in my hand, jotting
down words, sentences, and diagrams in my notebook.  I maintained this habit
during my entire studies.  Still today, I prefer to follow a lecture while
taking&amp;nbsp;notes.&lt;/p&gt;
&lt;p&gt;I view this in-class note-taking as a one-step process: I capture the teacher&amp;#8217;s
words on paper and the notes become directly usable for&amp;nbsp;revising.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure1" src="https://thewagner.net/images/note-taking-process-one-step.svg" title="In-class note-taking produces notes that I can directly use for            revising."&gt;&lt;/p&gt;
&lt;p&gt;When &lt;a href="https://thewagner.net/blog/2021/06/05/practicing-writing/"&gt;I write at work&lt;/a&gt;, I produce a lot of notes. For example,
during a meeting I capture the salient points of a discussion, but the
resulting notes, in their raw form, only make sense to me and to none of my
co-workers.  A meeting possesses much less structure than a university lecture,
the messy, somewhat unreadable in-meeting notes require an extra pass to render
them&amp;nbsp;usable.&lt;/p&gt;
&lt;p&gt;When I read a technical text, I take notes.  I don&amp;#8217;t underline or highlight
words in books; instead, I jot down the interesting word or concept together
with the page number.  Later, I go back to each notes&amp;#8217; page and form a complete
sentence about the concept or&amp;nbsp;idea.&lt;/p&gt;
&lt;p&gt;A few years ago, reading &lt;a href="https://www.soenkeahrens.de/en/takesmartnotes"&gt;How to Take Smart Notes&lt;/a&gt; by Sönke Ahrens
made me think about my own note-taking process which now involves three kinds
of&amp;nbsp;notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Fleeting note&lt;/em&gt;: temporary reminder of an idea, thought, or piece of&amp;nbsp;information.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Project note&lt;/em&gt;: information relevant to achieve a specific goal, often
  involving other&amp;nbsp;people.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Permanent note&lt;/em&gt;: distilled ideas and arguments that form the core of a
  knowledge&amp;nbsp;base.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The process still starts with the capture step, but it contains two more steps
which produce the project and permanent&amp;nbsp;notes:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure2" src="https://thewagner.net/images/note-taking-process-multi2.svg" title="Data flow in my two-step note-taking process"&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s see each step in&amp;nbsp;detail.&lt;/p&gt;
&lt;h1&gt;Capture&lt;/h1&gt;
&lt;p&gt;During the &lt;em&gt;capture&lt;/em&gt; step I write down any relevant information I want to hold
on for later.  I already mentioned writing meeting or literature notes; I jot
down anything that switches on that light bulb above my head. The capture
transforms an intangible idea into a fleeting&amp;nbsp;note.&lt;/p&gt;
&lt;p&gt;Since my school days, my capture method remained essentially the same.
Depending on my mood I draft words, create lists, or sketch shapes and arrows.
I don&amp;#8217;t follow any particular system; I characterize my technique as a mix of
linear and visual&amp;nbsp;note-taking.&lt;/p&gt;
&lt;p&gt;I haven&amp;#8217;t seen two people take notes the same way so I suspect any method that
produces legible written text yields usable fleeting notes.
&lt;a href="https://en.wikipedia.org/wiki/Note-taking"&gt;Wikipedia&lt;/a&gt; and many note-taking application vendors frame
note-taking as this capture&amp;nbsp;step.&lt;/p&gt;
&lt;p&gt;Capturing fleeting notes became almost automatic to me, but this step alone
doesn&amp;#8217;t produce useful notes.  I now believe the notes&amp;#8217; value only emerges when
I do a second pass over my fleeting&amp;nbsp;notes.&lt;/p&gt;
&lt;h1&gt;Who, What, When, Where,&amp;nbsp;Why&lt;/h1&gt;
&lt;p&gt;The activity, which I name after the &lt;a href="https://en.wikipedia.org/wiki/Five_Ws"&gt;Five Ws of journalism&lt;/a&gt;,
starts if a fleeting note belongs to a project.  As David Allen explains in
&lt;a href="https://en.wikipedia.org/wiki/Getting_Things_Done"&gt;Getting Things Done&lt;/a&gt; you cannot &lt;em&gt;do&lt;/em&gt; a project, you can only do
actions that bring you closer to the project&amp;#8217;s goals.  When processing a
project-relevant fleeting note, I identify actions and define the project&amp;#8217;s
next&amp;nbsp;action.&lt;/p&gt;
&lt;p&gt;In my personal system, I maintain a list of actions per project; the next
action appears as the first element.  At work, I store the project notes in
whatever system the team chooses.  The implementation doesn&amp;#8217;t matter as long as
the note reaches the people&amp;nbsp;involved.&lt;/p&gt;
&lt;h1&gt;Rephrase&lt;/h1&gt;
&lt;p&gt;If a note doesn&amp;#8217;t relate to a specific project, I write a &lt;em&gt;permanent note&lt;/em&gt; and
store it in my reference system.  These notes come in different kinds including
data sheets, manuals, literature review, definitions, and&amp;nbsp;outlines.&lt;/p&gt;
&lt;p&gt;For example, I keep a list of tools I require for replacing my bike&amp;#8217;s break
pads and a note detailing &lt;a href="https://git-scm.com"&gt;Git&lt;/a&gt; commands I use
infrequently. I have notes about concepts and ideas from articles and
conference talks, and I draft summaries of books I&amp;nbsp;read.&lt;/p&gt;
&lt;p&gt;Initially, I tried to segregate the different note kinds, but now I simply
place every non-project related note in a single&amp;nbsp;system.&lt;/p&gt;
&lt;p&gt;Most fleeting notes demand work to reach the reference system.  I rephrase the
recorded concept using my own words.  I write full sentences in one or two
paragraphs, preferably in active voice, and I avoid lists and bullet points.
For example, my permanent note about Paul Graham&amp;#8217;s essay  &lt;em&gt;Writes and Write
Nots&lt;/em&gt; reads as&amp;nbsp;follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In his essay &lt;a href="https://paulgraham.com/writes.html"&gt;Writes and Write Nots&lt;/a&gt; Paul
Graham, predicts that in couple of decades most people will loose their
ability to write.  Clear writing requires clear thinking which makes writing
fundamentally hard.  When you have a more prestigious job, you require to
write&amp;nbsp;more.&lt;/p&gt;
&lt;p&gt;Today generative &lt;span class="caps"&gt;AI&lt;/span&gt; tools may write for you, but they don&amp;#8217;t to the thinking
part.  Paul Graham&amp;#8217;s prediction that the world will split into those who
write and those who &amp;#8220;write not&amp;#8221;.  Following his previous argument, this
means we will have a split between &amp;#8220;thinks&amp;#8221; and &amp;#8220;think&amp;nbsp;nots&amp;#8221;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It took me only a few minutes to write these two paragraphs.  I can immediately
recall why this article resonated with me and explain it using my own words to
other people if I want&amp;nbsp;to.&lt;/p&gt;
&lt;p&gt;I admit, not all my notes look like this; sometimes I cannot find better words
than the original.  Sometimes I just copy over my fleeting notes and move on,
but when I skip the rephrase step I know I don&amp;#8217;t get the most out my&amp;nbsp;notes.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;In the past few years I adopted a two-step note-taking process.  I capture
ideas as fleeting notes.  For projects, I extract next actions from the
fleeting note and record a permanent note in a system the project team can
access.  Otherwise, I rephrase the fleeting note using my own words to create a
permanent note, which I store in a reference&amp;nbsp;system.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Homelab turns five</title><link href="https://thewagner.net/blog/2025/05/31/homelab-turns-five/" rel="alternate"/><published>2025-05-31T00:00:00+02:00</published><updated>2025-05-31T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2025-05-31:/blog/2025/05/31/homelab-turns-five/</id><summary type="html">&lt;p&gt;This day marks the fifth anniversary of my Homelab.  Five years ago, as a
&lt;span class="caps"&gt;COVID&lt;/span&gt;-19 lockdown project, I &lt;a href="https://thewagner.net/blog/2020/04/30/exploring-nix/"&gt;learned Nix&lt;/a&gt; and &lt;a href="https://thewagner.net/blog/2020/05/31/homelab/"&gt;installed
NixOS on my home computers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While my Homelab may not compete in sophistication with setups you find on
&lt;a href="https://www.reddit.com/r/homelab/"&gt;Reddit&lt;/a&gt;, I consider it a forerunner in
longevity and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This day marks the fifth anniversary of my Homelab.  Five years ago, as a
&lt;span class="caps"&gt;COVID&lt;/span&gt;-19 lockdown project, I &lt;a href="https://thewagner.net/blog/2020/04/30/exploring-nix/"&gt;learned Nix&lt;/a&gt; and &lt;a href="https://thewagner.net/blog/2020/05/31/homelab/"&gt;installed
NixOS on my home computers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While my Homelab may not compete in sophistication with setups you find on
&lt;a href="https://www.reddit.com/r/homelab/"&gt;Reddit&lt;/a&gt;, I consider it a forerunner in
longevity and maintainability.  I attribute this success to the use of Nix,
which I praised in many blog post&amp;nbsp;before.&lt;/p&gt;
&lt;p&gt;The current setup, which remained stable since 2020, doesn&amp;#8217;t represent the
first generation of my Homelab.  I started to use Ansible back in 2015 because
I had grown frustrated with the &amp;#8220;install and forget&amp;#8221; approach, where you
configure a system and then quickly forget the details, making future updates&amp;nbsp;difficult.&lt;/p&gt;
&lt;p&gt;In 2015 I built a &lt;a href="https://gitolite.com/gitolite/"&gt;Gitolite&lt;/a&gt; server on Debian
Linux.  A year later I could control my Christmas lights using Home Assistant
with the entire configuration represented as code.  I also built a container
host with &lt;span class="caps"&gt;LXC&lt;/span&gt;, an &lt;a href="https://owncloud.com/"&gt;ownCloud&lt;/a&gt; instance and a media&amp;nbsp;server.&lt;/p&gt;
&lt;p&gt;In 2017, because Ansible worked reasonably well on my servers, I started
writing a playbook for my primary working laptop.  I wanted to codify my
laptop&amp;#8217;s configuration but I couldn&amp;#8217;t build a reliable set of Ansible tasks and
playbooks that worked independently of machine&amp;#8217;s existing state.  I would
manually install new tools and struggled to document every change in Ansible.
Perhaps I lacked the discipline or I insisted on the wrong approach; eventually
I gave up.  I never finished the configuration scripts for my laptop. The
servers&amp;#8217; playbooks gradually stopped working because of the system updates and
other out of band&amp;nbsp;changes.&lt;/p&gt;
&lt;p&gt;Over the years I kept looking for a better software configuration system.  I
explored alternatives such as
&lt;a href="https://www.cdi.st/manual/latest/index.html"&gt;cdist&lt;/a&gt;,
&lt;a href="https://www.fabfile.org/"&gt;fabric&lt;/a&gt;, and
&lt;a href="https://joeyh.name/blog/propellor/"&gt;propellor&lt;/a&gt;, but none felt sufficiently
different to Ansible. They often had smaller user communities and more quirks.
I even used &lt;a href="https://saltproject.io/"&gt;Salt&lt;/a&gt; professionally and followed
&lt;a href="https://github.com/purpleidea/mgmt"&gt;mgmt&lt;/a&gt; for a&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;Finally, in 2020 I discovered Nix and I wrote my first &lt;a href="https://thewagner.net/blog/2020/05/31/homelab/"&gt;Homelab
post&lt;/a&gt; about it.  I firmly believe that if your hobby or job
involves managing servers, you should not use anything but&amp;nbsp;Nix.&lt;/p&gt;
&lt;p&gt;Happy birthday,&amp;nbsp;Homelab!&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Six months of CDK</title><link href="https://thewagner.net/blog/2025/02/15/six-months-of-cdk/" rel="alternate"/><published>2025-02-15T00:00:00+01:00</published><updated>2025-02-15T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2025-02-15:/blog/2025/02/15/six-months-of-cdk/</id><summary type="html">&lt;p&gt;Last August I started a new job.  I joined a team of engineers building cloud
infrastructure using the Amazon Web Services (&lt;span class="caps"&gt;AWS&lt;/span&gt;) Cloud Development Kit (&lt;span class="caps"&gt;CDK&lt;/span&gt;)
TypeScript library.  I have had extensive experience building on &lt;span class="caps"&gt;AWS&lt;/span&gt;, but I
haven&amp;#8217;t used this tool&amp;nbsp;professionally.&lt;/p&gt;
&lt;p&gt;In this article I describe my …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last August I started a new job.  I joined a team of engineers building cloud
infrastructure using the Amazon Web Services (&lt;span class="caps"&gt;AWS&lt;/span&gt;) Cloud Development Kit (&lt;span class="caps"&gt;CDK&lt;/span&gt;)
TypeScript library.  I have had extensive experience building on &lt;span class="caps"&gt;AWS&lt;/span&gt;, but I
haven&amp;#8217;t used this tool&amp;nbsp;professionally.&lt;/p&gt;
&lt;p&gt;In this article I describe my experience with the &lt;span class="caps"&gt;CDK&lt;/span&gt; and I will argue that, if
you can, you should prefer the &lt;span class="caps"&gt;CDK&lt;/span&gt; to any other tool when building cloud
infrastructure on &lt;span class="caps"&gt;AWS&lt;/span&gt;.&lt;/p&gt;
&lt;h1&gt;Infrastructure as&amp;nbsp;code&lt;/h1&gt;
&lt;p&gt;Cloud providers such as &lt;span class="caps"&gt;AWS&lt;/span&gt; expose thousands of management endpoints to
programmatically interact with compute, storage and networking resources.  In
particular, &lt;span class="caps"&gt;AWS&lt;/span&gt; groups related endpoints into &lt;em&gt;services&lt;/em&gt;, such as &lt;span class="caps"&gt;EC2&lt;/span&gt;, S3, just
to name two out of more than 400 from their&amp;nbsp;offering.&lt;/p&gt;
&lt;p&gt;I remember learning &lt;span class="caps"&gt;AWS&lt;/span&gt; back in 2018: I felt swamped by all the three letter
acronyms.  I didn&amp;#8217;t know if I needed &lt;span class="caps"&gt;EC2&lt;/span&gt;, &lt;span class="caps"&gt;ECS&lt;/span&gt; or &lt;span class="caps"&gt;EKS&lt;/span&gt;, or if &lt;span class="caps"&gt;EBS&lt;/span&gt; made more sense
for an instance inside a &lt;span class="caps"&gt;VPC&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Initially, I studied the most commonly used services using the &lt;span class="caps"&gt;AWS&lt;/span&gt; web console
used services.  For example, I clicked on the &amp;#8220;Launch new instance&amp;#8221; button on
the &lt;span class="caps"&gt;EC2&lt;/span&gt; console, answered a series of questions — often just accepting the
proposed default values —, then I watched the instance booting.  I traced the
details of the running instance to other resources to understand how they
interact.  This way I learned that running a single virtual machine instance
requires a machine image, a launch template, a volume, a network, and a bunch
of&amp;nbsp;permissions.&lt;/p&gt;
&lt;p&gt;While I appreciate the interactive and visual nature of the web console,
especially for learning, I can&amp;#8217;t build large systems by clicking around in my
web&amp;nbsp;browser.&lt;/p&gt;
&lt;p&gt;I specify the system&amp;#8217;s blueprint in plain text files, as source code, which a
computer can translate into programmatic calls to the cloud provider&amp;#8217;s &lt;span class="caps"&gt;API&lt;/span&gt;.  I
prefer this approach, commonly called &lt;a href="https://en.wikipedia.org/wiki/Infrastructure_as_code"&gt;infrastructure as code&lt;/a&gt;,
because the blueprint mirrors the engineering &lt;em&gt;intent&lt;/em&gt; and, using a version
control system, I can track how the intent changes as the project&amp;nbsp;evolves.&lt;/p&gt;
&lt;p&gt;I still use the web console every day, but mainly in &amp;#8220;read-only&amp;#8221; mode.  I
rarely use it to create or change resources, but I inspect and study the
resources the blueprint&amp;nbsp;creates.&lt;/p&gt;
&lt;h1&gt;CloudFormation&lt;/h1&gt;
&lt;p&gt;&lt;span class="caps"&gt;AWS&lt;/span&gt; CloudFormation, &lt;a href="https://aws.amazon.com/about-aws/whats-new/2011/02/25/introducing-aws-cloudformation/"&gt;announced&lt;/a&gt; in 2011, takes infrastructure
blueprints, called &lt;em&gt;templates&lt;/em&gt;, and provisions the required resources in the
right sequence taking into account any dependencies between resources.
CloudFormation can &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-basic-walkthrough.html"&gt;automatically deploy&lt;/a&gt; infrastructure into
&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/what-is-cfnstacksets.html"&gt;different regions&lt;/a&gt; using templates stored in &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/git-sync.html"&gt;Git
repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Despite its advanced capabilities CloudFormation gathered a bad reputation.  I
used to judge it based on the syntax of its specification language: a verbose
&lt;span class="caps"&gt;YAML&lt;/span&gt; configuration file sprinkled with awkward &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html"&gt;built-in
functions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I had to look beyond the syntax to realize that a CloudFormation template
represents a simple &lt;em&gt;data structure&lt;/em&gt;, built up from numbers, strings, lists and
maps.  You can generate, analyze and transform templates using any programming&amp;nbsp;tool.&lt;/p&gt;
&lt;p&gt;I believe &lt;span class="caps"&gt;AWS&lt;/span&gt; never wanted developers to write giant CloudFormation templates
by hand, but it didn&amp;#8217;t guide users what to do instead.  &lt;span class="caps"&gt;AWS&lt;/span&gt; engineers, while
working on an internal project, &lt;a href="https://aws.amazon.com/blogs/opensource/working-backwards-the-story-behind-the-aws-cloud-development-kit/"&gt;searched for a more expressive way&lt;/a&gt;
of writing infrastructure specifications.  Their ideas seeded the development
of the &lt;span class="caps"&gt;CDK&lt;/span&gt; which &lt;span class="caps"&gt;AWS&lt;/span&gt; announced in 2019 as their official CloudFormation
template&amp;nbsp;generator.&lt;/p&gt;
&lt;h1&gt;Cloud Development Kit (&lt;span class="caps"&gt;CDK&lt;/span&gt;)&lt;/h1&gt;
&lt;p&gt;The &lt;span class="caps"&gt;AWS&lt;/span&gt; Cloud Development Kit (&lt;span class="caps"&gt;CDK&lt;/span&gt;) library, written in TypeScript, generates
CloudFormation templates.  &lt;span class="caps"&gt;AWS&lt;/span&gt; developed &lt;a href="https://github.com/aws/jsii"&gt;JSii&lt;/a&gt;, a technology to expose
the TypeScript &lt;span class="caps"&gt;CDK&lt;/span&gt; modules to other popular programming languages such as
Python, Go and Java to attract developers from all these communities.  But,
instead of the programming languages, I suggest studying the &lt;span class="caps"&gt;CDK&lt;/span&gt;&amp;#8217;s programming
model to generate CloudFormation&amp;nbsp;templates.&lt;/p&gt;
&lt;h2&gt;Constructs&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/aws/constructs/tree/10.x"&gt;Construct library&lt;/a&gt; forms the core of the &lt;span class="caps"&gt;CDK&lt;/span&gt;.  The library has
no dependencies, and it defines&amp;nbsp;the &lt;code&gt;Construct&lt;/code&gt; interface modeling a piece of
system state.  A construct may contain other constructs, forming a tree
representing the infrastructure&amp;nbsp;blueprint.&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;CDK&lt;/span&gt; build process automatically generates large part of the &lt;span class="caps"&gt;CDK&lt;/span&gt; library
from &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-template-resource-type-ref.html"&gt;CloudFormation resource specifications&lt;/a&gt;.  For
example, the &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.CfnBucket.html"&gt;CfnBucket&lt;/a&gt; construct represents a mechanical
translation of the &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-s3-bucket.html"&gt;&lt;span class="caps"&gt;AWS&lt;/span&gt;::S3::Bucket&lt;/a&gt; CloudFormation resource
to TypeScript.  The &lt;span class="caps"&gt;AWS&lt;/span&gt; documentation refers to these objects as &lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/aws-cdk-layers/layer-1.html"&gt;Layer 1&lt;/a&gt;&amp;nbsp;constructs.&lt;/p&gt;
&lt;p&gt;You rarely use these generated objects because &lt;span class="caps"&gt;CDK&lt;/span&gt; engineers also created
&lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/aws-cdk-layers/layer-2.html"&gt;Layer 2&lt;/a&gt; constructs which equip Layer 1 constructs with reasonable
defaults, convenience methods and other syntactic sugar.  For example, the
Layer 2 &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.Bucket.html"&gt;Bucket&lt;/a&gt; construct by default creates an S3 bucket that follows
&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/security-best-practices.html"&gt;&lt;span class="caps"&gt;AWS&lt;/span&gt;&amp;#8217;s security recommendations&lt;/a&gt;.  Also, you can just&amp;nbsp;write&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;bucket.grantRead(ec2-instance)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which creates the necessary &lt;span class="caps"&gt;IAM&lt;/span&gt; policies so that the &lt;span class="caps"&gt;EC2&lt;/span&gt; instance can read
objects from the&amp;nbsp;bucket.&lt;/p&gt;
&lt;p&gt;Finally, constructs modeling application specific patterns live at &lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/aws-cdk-layers/layer-3.html"&gt;Layer
3&lt;/a&gt;.  For example, &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines-readme.html"&gt;&lt;span class="caps"&gt;CDK&lt;/span&gt; Pipelines&lt;/a&gt; construct library
coordinates many &lt;span class="caps"&gt;AWS&lt;/span&gt; services to create a deployment pipeline for a &lt;span class="caps"&gt;CDK&lt;/span&gt;
application.  This library showed me the leverage the &lt;span class="caps"&gt;CDK&lt;/span&gt; offers: in just a few
lines of code, I could create a continuous deployment pipeline that deploys my
infrastructure into three regions using two &lt;span class="caps"&gt;AWS&lt;/span&gt;&amp;nbsp;accounts.&lt;/p&gt;
&lt;p&gt;I admit, the first few times I read the documentation, I didn&amp;#8217;t pay close
attention to this layering.  When I develop with the &lt;span class="caps"&gt;CDK&lt;/span&gt;, I don&amp;#8217;t have to think
about this stratification: constructs at each layer present the same uniform
interface, allowing me to freely combine any constructs I need.  But,
understanding the difference between these layers shaped my expectations
towards specific&amp;nbsp;constructs.&lt;/p&gt;
&lt;p&gt;I view Layer 1 constructs as the platform&amp;#8217;s primitive operations.  Because
every &lt;span class="caps"&gt;AWS&lt;/span&gt; service integrates with CloudFormation, often from the day of its
public release, the corresponding Layer 1 construct quickly becomes available
in the &lt;span class="caps"&gt;CDK&lt;/span&gt; via automatic translation process I mentioned earlier.  In contrast,
the handwritten Layer 2 constructs, if they exist,  often introduce
higher-level abstractions which may or may not work for your use&amp;nbsp;case.&lt;/p&gt;
&lt;p&gt;Take the &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Vpc.html"&gt;&lt;span class="caps"&gt;VPC&lt;/span&gt;&lt;/a&gt; Layer 2 construct, for instance.  It comes with generous
defaults setting up two Availability Zones and &lt;span class="caps"&gt;NAT&lt;/span&gt; gateways in both. These make
sense when you design for high availability, but feels like overkill if you
just need to launch a few development machines.  Or, sometimes you want to
assign secondary &lt;span class="caps"&gt;IP&lt;/span&gt; addresses to instances running in a &lt;span class="caps"&gt;VPC&lt;/span&gt;, but this construct
doesn&amp;#8217;t allow for that; you&amp;#8217;d have to build the missing bits using Layer 1&amp;nbsp;constructs.&lt;/p&gt;
&lt;p&gt;Even with these caveats, I&amp;#8217;ve found Layer 2 constructs generally effective in
my projects.  I always try to use them first before I consider Layer 1
constructs, or even raw&amp;nbsp;CloudFormation.&lt;/p&gt;
&lt;h2&gt;Escape&amp;nbsp;hatches&lt;/h2&gt;
&lt;p&gt;You can import existing CloudFormation templates, written in &lt;span class="caps"&gt;YAML&lt;/span&gt; or &lt;span class="caps"&gt;JSON&lt;/span&gt;, and
treat them as &lt;span class="caps"&gt;CDK&lt;/span&gt; Constructs:  I had used a small CloudFormation template in my
project; it worked seamlessly, but after a few days I just rewrote it in&amp;nbsp;TypeScript.&lt;/p&gt;
&lt;p&gt;In some cases, you may &lt;a href="https://github.com/aws-cloudformation/cloudformation-coverage-roadmap/issues/1979"&gt;find&lt;/a&gt; that a CloudFormation resource doesn&amp;#8217;t
cover all configuration options of a resource.  In this case you can fall back
to &lt;span class="caps"&gt;AWS&lt;/span&gt; &lt;span class="caps"&gt;SDK&lt;/span&gt; calls triggered on CloudFormation stack operation events such as
Create, Delete, or Update.  The &lt;span class="caps"&gt;CDK&lt;/span&gt;&amp;#8217;s &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.custom_resources.AwsCustomResource.html"&gt;AwsCustomResource&lt;/a&gt;
construct allows you to bridge any gap in the CloudFormation&amp;nbsp;coverage.&lt;/p&gt;
&lt;h2&gt;Tooling&lt;/h2&gt;
&lt;p&gt;The &lt;span class="caps"&gt;CDK&lt;/span&gt;&amp;#8217;s availability across many programming languages always intrigued me.
Advocates often present this as a key benefit: a team developing a TypeScript
application, for example, can now write its infrastructure definition in
TypeScript as well.  This eliminates the need to learn a new domain-specific
language.  An argument I&amp;#8217;ll call &amp;#8220;appeal to familiarity&amp;#8221; and one I certainly
don&amp;#8217;t disagree with.  But, looking again beyond the language syntax, I think
leveraging an existing programming library ecosystem provides the most&amp;nbsp;benefit.&lt;/p&gt;
&lt;p&gt;When I started using the &lt;span class="caps"&gt;CDK&lt;/span&gt; I didn&amp;#8217;t know TypeScript.  I had used JavaScript
and many other programming languages, so learning the basics of TypeScript
didn&amp;#8217;t pose a problem for me: the web community produced an incredible amount
of learning material, libraries, package managers and other tools.  After a few
hours I already studied the &amp;#8220;&lt;span class="caps"&gt;CDK&lt;/span&gt; world&amp;#8221;, because the TypeScript scaffolding
just&amp;nbsp;worked.&lt;/p&gt;
&lt;h1&gt;Difficulties&lt;/h1&gt;
&lt;p&gt;I praised the &lt;span class="caps"&gt;CDK&lt;/span&gt;&amp;#8217;s construct-based component model and its integration with
other &lt;span class="caps"&gt;AWS&lt;/span&gt; tools and with existing programming language ecosystems.  But during
my six months journey I faced also a few difficulties which I describe&amp;nbsp;next.&lt;/p&gt;
&lt;h2&gt;Moving&amp;nbsp;resources&lt;/h2&gt;
&lt;p&gt;I like maintaining code which groups resource definitions into high-level,
application-specific modules like &amp;#8220;storage layer&amp;#8221; or a &amp;#8220;compute cell&amp;#8221; because
the structure provides me context about a particular resource&amp;#8217;s role in the
application.  As I mentioned before, constructs provide a great modeling tool
for building up these&amp;nbsp;modules.&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;CDK&lt;/span&gt; computes a resource&amp;#8217;s unique identity based on its &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/identifiers.html#identifiers-unique-ids"&gt;path within the
construct
tree&lt;/a&gt;.
Hence, when you move a resource from one high-level construct to another,
CloudFormation interprets this change as an instruction to recreate that
resource under a new identity.  Depending on the resource, this might cause
service interruption, data loss, or&amp;nbsp;both.&lt;/p&gt;
&lt;p&gt;A technique I learned from the &lt;span class="caps"&gt;CDK&lt;/span&gt; documentation protects against accidental
resource destruction:  I add a unit test that asserts the stability of the
critical resource&amp;#8217;s logical&amp;nbsp;identifier.&lt;/p&gt;
&lt;h2&gt;Using deferred&amp;nbsp;values&lt;/h2&gt;
&lt;p&gt;In a CloudFormation template a &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/intrinsic-function-reference-ref.html"&gt;Ref&lt;/a&gt; refers another resource&amp;#8217;s property.
During deployment, the CloudFormation service orders resource creation such
that it can substitute&amp;nbsp;the &lt;code&gt;Ref&lt;/code&gt; with the property&amp;#8217;s actual&amp;nbsp;value.&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;CDK&lt;/span&gt; models references using &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/tokens.html"&gt;tokens&lt;/a&gt;. These tokens present as
regular TypeScript strings, but their values use a special encoding.  This
design choice lets you write code that looks like direct property access, which
the &lt;span class="caps"&gt;CDK&lt;/span&gt; translates&amp;nbsp;into &lt;code&gt;Ref&lt;/code&gt;s when needed.  On the flip slide, you lack a
clear signal when you handle one of these deferred&amp;nbsp;values.&lt;/p&gt;
&lt;p&gt;Fortunately, most of the code I write avoids inspecting or manipulating tokens.
If you develop a construct library I suggest studying &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/tokens.html"&gt;how to check for
unresolved tokens in your constructs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;EKS&lt;/span&gt;&amp;nbsp;Blueprints&lt;/h2&gt;
&lt;p&gt;The final point I want to make doesn&amp;#8217;t concern the &lt;span class="caps"&gt;CDK&lt;/span&gt; itself; it highlights a
self-inflicted problem that can surface in any project.  At work, we use the
&lt;a href="https://github.com/awslabs/cdk-eks-blueprints"&gt;&lt;span class="caps"&gt;EKS&lt;/span&gt; Blueprints library&lt;/a&gt; which, to me, creates more issues than
it solves.  Instead of using plain constructs, this library layers a bespoke
dependency injection system on top of the &lt;span class="caps"&gt;CDK&lt;/span&gt;&amp;#8217;s existing construct programming
model. Also, this implementation heavily relies on async/await, which makes
escaping its patterns incredibly&amp;nbsp;difficult.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;If you build on &lt;span class="caps"&gt;AWS&lt;/span&gt;, I suggest using the Cloud Development Kit.  You may have
reasons to choose something else, but I believe you should consider the &lt;span class="caps"&gt;CDK&lt;/span&gt;
first before anything else.  For learning, I recommend the &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/home.html"&gt;official
documentation&lt;/a&gt;, and especially the &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/best-practices.html"&gt;best practices&lt;/a&gt;
section which offers many useful tips on structuring your &lt;span class="caps"&gt;AWS&lt;/span&gt; accounts,
deployment pipelines, and &lt;span class="caps"&gt;CDK&lt;/span&gt; code.  Finally, use any constructs from the &lt;span class="caps"&gt;CDK&lt;/span&gt;,
but think twice before importing other construct&amp;nbsp;libraries.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Year 2024 in review</title><link href="https://thewagner.net/blog/2024/12/31/year-2024-in-review/" rel="alternate"/><published>2024-12-31T00:00:00+01:00</published><updated>2024-12-31T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2024-12-31:/blog/2024/12/31/year-2024-in-review/</id><summary type="html">&lt;p&gt;I started the 2024 with an intense training program for the &lt;a href="https://training.thewagner.net/blog/2024/04/28/20-km-de-lausanne-2024/"&gt;20 km of
Lausanne&lt;/a&gt;.
I moved to a new place, I rode my &lt;a href="https://training.thewagner.net/blog/2024/03/28/cervelo-caledonia-5/"&gt;new
bike&lt;/a&gt; as
much as I could and I started a new job.  Fortunately, next to all these
changes in my life, I could still find …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I started the 2024 with an intense training program for the &lt;a href="https://training.thewagner.net/blog/2024/04/28/20-km-de-lausanne-2024/"&gt;20 km of
Lausanne&lt;/a&gt;.
I moved to a new place, I rode my &lt;a href="https://training.thewagner.net/blog/2024/03/28/cervelo-caledonia-5/"&gt;new
bike&lt;/a&gt; as
much as I could and I started a new job.  Fortunately, next to all these
changes in my life, I could still find some time for&amp;nbsp;writing.&lt;/p&gt;
&lt;h1&gt;Articles&lt;/h1&gt;
&lt;p&gt;In April, I &lt;a href="https://thewagner.net/blog/2024/04/19/the-stupidity-paradox/"&gt;reviewed&lt;/a&gt; &lt;em&gt;The Stupidity Paradox&lt;/em&gt;, a book exploring the
role of functional stupidity in contemporary organizations.  I liked writing
this article because it helped me to internalize the content of the&amp;nbsp;book.&lt;/p&gt;
&lt;p&gt;At work, I heard many complaints about &lt;em&gt;software quality&lt;/em&gt;, but nobody could
define what quality meant for them.  I decided to &lt;a href="https://thewagner.net/blog/2024/06/25/software-quality/"&gt;review the chapters on
quality&lt;/a&gt; from &lt;em&gt;Facts and Fallacies of Software Engineering&lt;/em&gt;.  When I
shared this post with a friend, he immediately suggested me to read &lt;em&gt;The Zen
and Art of Motorcycle Maintenance&lt;/em&gt;. In this book the protagonist becomes insane
during his quest to define quality.  &lt;a href="https://thewagner.net/blog/2024/06/25/software-quality/"&gt;In the article&lt;/a&gt; I cite seven
attributes which form a working definition of quality for software teams
without risking&amp;nbsp;madness.&lt;/p&gt;
&lt;p&gt;In the summer, I had some time between jobs to tinker in my &lt;a href="https://github.com/wagdav/homelab"&gt;Homelab&lt;/a&gt;.
In &lt;a href="https://thewagner.net/blog/2024/07/31/raspberry-pi-camera-on-nixos/"&gt;this article&lt;/a&gt; I explain how I use my Raspberry Pi Camera module with&amp;nbsp;NixOS.&lt;/p&gt;
&lt;p&gt;Finally, as in the past few years, in December I spent my free time solving the
&lt;a href="https://thewagner.net/blog/2024/12/25/advent-of-code-2024/"&gt;Advent of Code&lt;/a&gt;&amp;nbsp;puzzles.&lt;/p&gt;
&lt;h1&gt;Books&lt;/h1&gt;
&lt;p&gt;I read Liu Cixin&amp;#8217;s &lt;em&gt;Remembrance of Earth&amp;#8217;s Past&lt;/em&gt; series in English: &lt;em&gt;The
Three-Body Problem&lt;/em&gt;, &lt;em&gt;The Dark Forest&lt;/em&gt; and &lt;em&gt;Death&amp;#8217;s End&lt;/em&gt;.  I found these books
less captivating than the &lt;em&gt;Expanse&lt;/em&gt;, the last big science fiction series I had
read.  Instead, I enjoyed watching the Netflix &lt;span class="caps"&gt;TV&lt;/span&gt;&amp;nbsp;adaptation.&lt;/p&gt;
&lt;p&gt;During vacation, I found Jack London&amp;#8217;s &lt;em&gt;Martin Eden&lt;/em&gt; on a public bookshelf.  A
random pick that became my best read of the year: after a thousand pages of
science fiction the story of a struggling autodidact writer came as a breath of
fresh&amp;nbsp;air.&lt;/p&gt;
&lt;p&gt;Thanks for reading my blog and happy&amp;nbsp;2025!&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Advent of Code 2024</title><link href="https://thewagner.net/blog/2024/12/25/advent-of-code-2024/" rel="alternate"/><published>2024-12-25T00:00:00+01:00</published><updated>2024-12-25T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2024-12-25:/blog/2024/12/25/advent-of-code-2024/</id><summary type="html">&lt;p&gt;Solving the Advent of Code 2024 puzzles in&amp;nbsp;Clojure.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Since 2020, every year I solve the &lt;a href="https://adventofcode.com/"&gt;Advent of Code&lt;/a&gt;
puzzles.  Also, every year I write an experience report about my 25+ day
journey in December.  Read my thoughts about previous years here:
&lt;a href="https://thewagner.net/blog/2020/12/25/advent-of-code-2020/"&gt;2020&lt;/a&gt;, &lt;a href="https://thewagner.net/blog/2021/12/25/advent-of-code-2021/"&gt;2021&lt;/a&gt;, &lt;a href="https://thewagner.net/blog/2022/12/25/advent-of-code-2022/"&gt;2022&lt;/a&gt; and &lt;a href="https://thewagner.net/blog/2023/12/25/advent-of-code-2023/"&gt;2023&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: If you still work or plan to work on the puzzles, stop
reading&amp;nbsp;now.&lt;/p&gt;
&lt;h1&gt;Puzzles&lt;/h1&gt;
&lt;p&gt;Between December 1 and December 25, a programming puzzle appears every day on
the Advent of Code website.  Each problem has two parts, the second part
unlocks after you complete the first.  To understand each day&amp;#8217;s puzzle, go to
the website and read the full description (for example &lt;a href="https://adventofcode.com/2024/day/1"&gt;Day 1: Historian
Hysteria&lt;/a&gt;).&lt;/p&gt;
&lt;h1&gt;Setup&lt;/h1&gt;
&lt;p&gt;My setup and goal remain the same as in the previous years: I use Clojure and I
try to write succinct and comprehensible&amp;nbsp;programs.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t have a specific library of helper functions for the Advent of Code, but
I have a &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/search.clj#L30"&gt;best-first search implementation&lt;/a&gt; that I find useful in many
problems. This year &amp;#8212; in particular in days &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day16.clj"&gt;16&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day18.clj"&gt;18&lt;/a&gt;, and
&lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day20.clj"&gt;20&lt;/a&gt; &amp;#8212; I expressed the solution using this&amp;nbsp;function.&lt;/p&gt;
&lt;p&gt;My &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day16.clj"&gt;Day 16&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day22.clj"&gt;Day 22&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day23.clj"&gt;Day 23&lt;/a&gt; solutions run for about
a minute, but I didn&amp;#8217;t have the energy to optimize&amp;nbsp;them.&lt;/p&gt;
&lt;h1&gt;Highlights&lt;/h1&gt;
&lt;p&gt;The first difficulty arrived on &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day12.clj"&gt;Day 12&lt;/a&gt;.  The puzzle asked for counting
the straight edges of polygonal &amp;#8220;gardens&amp;#8221;.  Initially I didn&amp;#8217;t find a good
approach for identifying a garden&amp;#8217;s boundary.  When I started to track the
normal of each point that form the boundary, my solution started to make&amp;nbsp;sense.&lt;/p&gt;
&lt;p&gt;I solved &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day13.clj"&gt;Day 13&lt;/a&gt; with pen and paper then I implemented the resulting
formula in&amp;nbsp;code.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day14.clj"&gt;Day 14&lt;/a&gt; had a picture of a Christmas tree hidden in the solution, so I&amp;nbsp;wrote:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(defn solve-part2 [input]
  (first (🎄 input)))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day15.clj"&gt;Day 15&lt;/a&gt; reminded me of
&lt;a href="https://en.wikipedia.org/wiki/Sokoban"&gt;Sokoban&lt;/a&gt;, one of the first games I
played on a computer.  I enjoyed this puzzle even if the second part of took me
a few attempts to get it right.  I experimented with using Clojure&amp;#8217;s dynamic
bindings to write  code that solve both parts of the&amp;nbsp;puzzle.&lt;/p&gt;
&lt;p&gt;Debugging the assembly code in the second part of &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day17.clj"&gt;Day 17&lt;/a&gt; went much
better than in a &lt;a href="https://adventofcode.com/2021/day/24"&gt;similar problem in
2021&lt;/a&gt;.  I worked on this problem together
with a colleague which made it even more&amp;nbsp;fun.&lt;/p&gt;
&lt;p&gt;I couldn&amp;#8217;t solve the second part of &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day21.clj"&gt;Day 21&lt;/a&gt;.  The puzzle asked to find
a shortest command sequence to control a robot pressing buttons on a numeric
keypad using a series of directional keypads.  I keep thinking about this
problem, but so far I didn&amp;#8217;t have the motivation to go back to&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;On &lt;a href="https://github.com/wagdav/advent-of-code/blob/main/src/aoc2024/day24.clj"&gt;Day 24&lt;/a&gt; I didn&amp;#8217;t write any code for the second part.  The puzzle
asked for finding four incorrectly wired logic gates of a &lt;a href="https://en.wikipedia.org/wiki/Adder_(electronics)#Full_adder"&gt;full
adder&lt;/a&gt;.  Using
Graphviz, I generated a diagram from the puzzle input and I looked for nodes
which caused visible&amp;nbsp;irregularities.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I could solve all but one problem during the 2024 Advent of Code: my best year
so&amp;nbsp;far.&lt;/p&gt;
&lt;p&gt;You can read the code of my solutions on &lt;a href="https://github.com/wagdav/advent-of-code"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Acknowledgments&lt;/h1&gt;
&lt;p&gt;Thanks &lt;a href="https://twitter.com/ericwastl"&gt;Eric Wastl&lt;/a&gt; for creating and running
&lt;a href="https://adventofcode.com"&gt;Advent of Code&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>NixOS on the Lenovo Carbon X1 (Gen 12)</title><link href="https://thewagner.net/blog/2024/09/10/nixos-on-the-lenovo-carbon-x1-gen-12/" rel="alternate"/><published>2024-09-10T00:00:00+02:00</published><updated>2024-09-10T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2024-09-10:/blog/2024/09/10/nixos-on-the-lenovo-carbon-x1-gen-12/</id><summary type="html">&lt;p&gt;My new &lt;a href="https://en.wikipedia.org/wiki/ThinkPad_X1_series#X1_Carbon_Gen_12"&gt;Lenovo X1 Carbon Gen 12&lt;/a&gt; arrived today.  I plan to use this
computer as my personal workstation for the coming years. I&amp;#8217;ve been watching
the evolution of the X1 Carbon series for a while; I was convinced that this
is the right model for me.  I don …&lt;/p&gt;</summary><content type="html">&lt;p&gt;My new &lt;a href="https://en.wikipedia.org/wiki/ThinkPad_X1_series#X1_Carbon_Gen_12"&gt;Lenovo X1 Carbon Gen 12&lt;/a&gt; arrived today.  I plan to use this
computer as my personal workstation for the coming years. I&amp;#8217;ve been watching
the evolution of the X1 Carbon series for a while; I was convinced that this
is the right model for me.  I don&amp;#8217;t need extreme performance and I appreciate
its small size and light&amp;nbsp;structure.&lt;/p&gt;
&lt;p&gt;The new X1 replaces a &lt;a href="https://en.wikipedia.org/wiki/ThinkPad_X_series#X230"&gt;Lenovo X230&lt;/a&gt; which I used for twelve years.  The
hardware is still in a good shape and the battery lasts for a few hours. But
it&amp;#8217;s just too slow even for browsing the&amp;nbsp;Internet.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/wagdav/homelab"&gt;I run NixOS&lt;/a&gt; on every computer I own and the new X1 is no exception.
In a few minutes I could replicate my current configuration on the new laptop.
On the X1 I decided to use &lt;a href="https://en.wikipedia.org/wiki/ZFS"&gt;&lt;span class="caps"&gt;ZFS&lt;/span&gt;&lt;/a&gt;, a file system I like to learn more
about.  Also, the disk partitioning scheme is now &lt;a href="https://github.com/wagdav/homelab/blob/30c6689308c65af2588fbcfce4c7a5f6a7d246ef/x1.nix"&gt;defined
declaratively&lt;/a&gt; using &lt;a href="https://github.com/nix-community/disko"&gt;disko&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When I first booted NixOS 24.05 with its default 6.6 &lt;span class="caps"&gt;LTS&lt;/span&gt; kernel, the &lt;span class="caps"&gt;HDMI&lt;/span&gt; port
and the sound didn&amp;#8217;t work.  I tried a few more recent kernel versions and I
found that since version 6.8.12 everything works.  Currently my system runs&amp;nbsp;6.10.2.&lt;/p&gt;
&lt;h1&gt;Acknowledgement&lt;/h1&gt;
&lt;p&gt;Thanks Kornél for helping me with the Lenovo hardware specifications, disko and &lt;span class="caps"&gt;ZFS&lt;/span&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Raspberry Pi camera on NixOS</title><link href="https://thewagner.net/blog/2024/07/31/raspberry-pi-camera-on-nixos/" rel="alternate"/><published>2024-07-31T00:00:00+02:00</published><updated>2024-07-31T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2024-07-31:/blog/2024/07/31/raspberry-pi-camera-on-nixos/</id><summary type="html">&lt;p&gt;In this article, I describe how I configured my Raspberry Pi v1 camera module
on my Raspberry Pi 3 running&amp;nbsp;NixOS.&lt;/p&gt;
&lt;p&gt;The Raspberry Pi &lt;span class="caps"&gt;OS&lt;/span&gt; has &lt;a href="https://www.raspberrypi.com/documentation/computers/camera_software.html#configuration"&gt;excellent support&lt;/a&gt; for many
camera modules.  If you run the officially supported operating system, most
cameras work without any further&amp;nbsp;configuration.&lt;/p&gt;
&lt;p&gt;In my &lt;a href="https://github.com/wagdav/homelab"&gt;Homelab …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this article, I describe how I configured my Raspberry Pi v1 camera module
on my Raspberry Pi 3 running&amp;nbsp;NixOS.&lt;/p&gt;
&lt;p&gt;The Raspberry Pi &lt;span class="caps"&gt;OS&lt;/span&gt; has &lt;a href="https://www.raspberrypi.com/documentation/computers/camera_software.html#configuration"&gt;excellent support&lt;/a&gt; for many
camera modules.  If you run the officially supported operating system, most
cameras work without any further&amp;nbsp;configuration.&lt;/p&gt;
&lt;p&gt;In my &lt;a href="https://github.com/wagdav/homelab"&gt;Homelab&lt;/a&gt; I don&amp;#8217;t use the Raspberry Pi &lt;span class="caps"&gt;OS&lt;/span&gt;, but I run NixOS on all
my computers, including the Raspberry Pi.  NixOS works well on the Pi, but the
camera module I own needs a special&amp;nbsp;configuration.&lt;/p&gt;
&lt;h1&gt;The &amp;#8220;new&amp;#8221; camera&amp;nbsp;stack&lt;/h1&gt;
&lt;p&gt;Four years ago, the Raspberry Pi team &lt;a href="https://www.raspberrypi.com/news/an-open-source-camera-stack-for-raspberry-pi-using-libcamera/"&gt;released a new camera
stack&lt;/a&gt; that provides better access to the internals of
the camera system.  Today, the old stack using Broadcom proprietary software is
unsupported and obsolete.  Unfortunately, many online instructions and tutorials
&lt;a href="https://forums.raspberrypi.com/viewtopic.php?t=362707"&gt;still refer to the Broadcom stack&lt;/a&gt; which renders them
irrelevant to the modern camera&amp;nbsp;stack.&lt;/p&gt;
&lt;p&gt;The new camera stack comprises four&amp;nbsp;layers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Linux kernel with board-specific&amp;nbsp;configuration&lt;/li&gt;
&lt;li&gt;Camera-specific&amp;nbsp;drivers&lt;/li&gt;
&lt;li&gt;The libcamera&amp;nbsp;library&lt;/li&gt;
&lt;li&gt;rpicam-apps camera utilities for taking photos and&amp;nbsp;videos&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The next sections describe how I configured these components on NixOS to use a
Raspberry Pi v1 camera module (Omnivision &lt;span class="caps"&gt;OV5647&lt;/span&gt;) with my Raspberry Pi&amp;nbsp;3B.&lt;/p&gt;
&lt;h2&gt;Kernel&lt;/h2&gt;
&lt;p&gt;The official NixOS installer works well on the Raspberry Pi.  However, the camera
modules require some subsystems that are not enabled by&amp;nbsp;default.&lt;/p&gt;
&lt;p&gt;Fortunately, it&amp;#8217;s easy to switch to a kernel tailored to the Raspberry Pi.  For
my model 3B, I select&amp;nbsp;the &lt;code&gt;linux_rp3&lt;/code&gt; kernel&amp;nbsp;package:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pkgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;boot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kernelPackages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pkgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;linuxKernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;linux_rpi3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Actually, I don&amp;#8217;t adjust this parameter in &lt;a href="https://github.com/wagdav/homelab/blob/c69d43d1b192070e3e741f7e7dafdc1fbb1e8c74/host-rp3.nix"&gt;my configuration&lt;/a&gt;,
but I import&amp;nbsp;the &lt;code&gt;raspberry-pi-3&lt;/code&gt; module from
&lt;a href="https://github.com/NixOS/nixos-hardware/blob/a59f00f5ac65b19382617ba00f360f8bc07ed3ac/raspberry-pi/3/default.nix#L7"&gt;nixos-hardware&lt;/a&gt; which selects the correct kernel and tunes
a few other parameters&amp;nbsp;too.&lt;/p&gt;
&lt;h2&gt;Camera driver (&lt;span class="caps"&gt;OV5647&lt;/span&gt;)&lt;/h2&gt;
&lt;p&gt;The Raspberry Pi v1 camera module uses an Omnivision &lt;span class="caps"&gt;OV5647&lt;/span&gt; image sensor.  We
need to describe the &lt;span class="caps"&gt;OV5647&lt;/span&gt; hardware to the kernel so that the sensor can be
controlled via the respective system calls.  The data structure and language
for describing hardware is called the &lt;em&gt;device tree&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is NixOS configuration block that enables the image&amp;nbsp;sensor:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;{ pkgs, ...}:
{
  hardware.deviceTree.filter = &amp;quot;bcm2837-rpi-3*&amp;quot;;
  hardware.deviceTree.overlays = [
    name = &amp;quot;ov5647-overlay&amp;quot;;
    dtsText = &amp;#39;&amp;#39;&amp;#39;
       ...ELIDED...
    &amp;#39;&amp;#39;&amp;#39;;
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For brevity, I omitted the value of&amp;nbsp;the &lt;code&gt;dtsText&lt;/code&gt;.  In my Homelab repository you
can read the full &lt;a href="https://github.com/wagdav/homelab/blob/c69d43d1b192070e3e741f7e7dafdc1fbb1e8c74/modules/camera-rpi-v1/default.nix#L34"&gt;device tree overlay configuration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;dtsText&lt;/code&gt; string is a copy of the file
&lt;a href="https://github.com/raspberrypi/linux/blob/rpi-6.1.y/arch/arm/boot/dts/overlays/ov5647-overlay.dts"&gt;ov5467-overlay.dts&lt;/a&gt; from the Linux kernel source with one
modification: I changed&amp;nbsp;the &lt;code&gt;compatible&lt;/code&gt; property&amp;nbsp;from &lt;code&gt;bcm2835&lt;/code&gt; to &lt;code&gt;bcm2837&lt;/code&gt;.
It turns out the &lt;span class="caps"&gt;OV546&lt;/span&gt; device tree overlay is compatible with both &lt;span class="caps"&gt;BCM&lt;/span&gt;
chipsets, but I don&amp;#8217;t understand why overlay&amp;#8217;s source doesn&amp;#8217;t reflect&amp;nbsp;this.&lt;/p&gt;
&lt;p&gt;I learned about this technique in &lt;a href="https://github.com/NixOS/nixpkgs/issues/125354"&gt;a GitHub issue
comment&lt;/a&gt;. It works™, the kernel
recognizes the image sensor on the &lt;span class="caps"&gt;I2C&lt;/span&gt;&amp;nbsp;bus:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/sys/bus/i2c/devices/10-0036/name
ov5647
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It was hard to get the device tree overlay working, but I&amp;#8217;m not entirely
satisfied:  fiddling with the device tree source files doesn&amp;#8217;t
feel&amp;nbsp;right.&lt;/p&gt;
&lt;p&gt;Fortunately, the hardware configuration is done. Next, the software&amp;nbsp;stack.&lt;/p&gt;
&lt;h2&gt;libcamera&lt;/h2&gt;
&lt;p&gt;The libcamera library drives the Raspberry Pi&amp;#8217;s camera system directly from the
Linux kernel, with minimal proprietary code running on the Broadcom &lt;span class="caps"&gt;GPU&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;libcamera is part of &lt;a href="https://github.com/NixOS/nixpkgs/blob/4b616a8ecce7aaceea5360f9724065c182dc016f/pkgs/by-name/li/libcamera/package.nix"&gt;nixpkgs&lt;/a&gt;, but it&amp;#8217;s built without
support for the Raspberry Pi.  I developed a &lt;a href="https://github.com/wagdav/homelab/blob/c69d43d1b192070e3e741f7e7dafdc1fbb1e8c74/modules/camera-rpi-v1/overlays/libcamera.nix"&gt;Nix package
overlay&lt;/a&gt;, based on the &lt;a href="https://www.raspberrypi.com/documentation/computers/camera_software.html#build-libcamera-and-rpicam-apps"&gt;Raspberry Pi specific libcamera
instructions&lt;/a&gt;, which the compiles libcamera with a few
additional&amp;nbsp;flags:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mesonFlags = old.mesonFlags ++ [
  &amp;quot;-Dcam=disabled&amp;quot;
  &amp;quot;-Dgstreamer=disabled&amp;quot;
  &amp;quot;-Dipas=rpi/vc4,rpi/pisp&amp;quot;
  &amp;quot;-Dpipelines=rpi/vc4,rpi/pisp&amp;quot;
];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The upstream libcamera package uses the Meson build system.  In the previous&amp;nbsp;snippet, &lt;code&gt;old.mesonFlags&lt;/code&gt; refers to the upstream package&amp;#8217;s build flags.  The
overlay appends to the original flag list enabling the Raspberry Pi specific
Image Processing Algorithms (IPAs) and&amp;nbsp;pipelines.&lt;/p&gt;
&lt;p&gt;This example shows off the strength of the Nix Packages overlay systems: the
overlay describes the differences from the upstream package&amp;#8217;s build
instructions, like a &lt;em&gt;patch&lt;/em&gt; representing the differences between two versions
of a text&amp;nbsp;file.&lt;/p&gt;
&lt;h2&gt;rpicam-apps&lt;/h2&gt;
&lt;p&gt;rpicam-apps is a set of command line applications, built on top of libcamera,
to capture images and video from a Raspberry Pi&amp;nbsp;camera.&lt;/p&gt;
&lt;p&gt;Based on a &lt;a href="https://github.com/NixOS/nixpkgs/pull/281803"&gt;draft pull-request in nixpkgs&lt;/a&gt;, I wrote &lt;a href="https://github.com/wagdav/homelab/blob/c69d43d1b192070e3e741f7e7dafdc1fbb1e8c74/modules/camera-rpi-v1/rpicam-apps.nix"&gt;a Nix
derivation&lt;/a&gt; which builds rpicam-apps using my own libcamera
build and enabling only a minimal set of features.  For example, I deactivate
support for preview windows and advanced post-processing&amp;nbsp;capabilities.&lt;/p&gt;
&lt;h1&gt;Picture&amp;nbsp;time&lt;/h1&gt;
&lt;p&gt;I collected the configuration I described in the previous sections in a &lt;a href="https://github.com/wagdav/homelab/blob/c69d43d1b192070e3e741f7e7dafdc1fbb1e8c74/modules/camera-rpi-v1/default.nix"&gt;NixOS
module&lt;/a&gt; which is imported from my &lt;a href="https://github.com/wagdav/homelab/blob/c69d43d1b192070e3e741f7e7dafdc1fbb1e8c74/host-rp3.nix"&gt;Raspberry Pi 3 host
configuration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After the configuration is deployed on the device, I can list the available&amp;nbsp;cameras:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ rpicam-still --list-cameras
Available cameras
-----------------
0 : ov5647 [2592x1944 10-bit GBRG] (/base/soc/i2c0mux/i2c@1/ov5647@36)
    Modes: &amp;#39;SGBRG10_CSI2P&amp;#39; : 640x480 [58.92 fps - (16, 0)/2560x1920 crop]
                             1296x972 [43.25 fps - (0, 0)/2592x1944 crop]
                             1920x1080 [30.62 fps - (348, 434)/1928x1080 crop]
                             2592x1944 [15.63 fps - (0, 0)/2592x1944 crop]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And, I can take a&amp;nbsp;picture:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;rpicam-still --output test-image.jpg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I won&amp;#8217;t try to impress you with the quality of the recorded image.  The v1
camera module is &lt;a href="https://www.raspberrypi.com/news/camera-board-available-for-sale/"&gt;old&lt;/a&gt;, the modules available today have much better
sensors and&amp;nbsp;optics.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I use NixOS because the operating system is described in a declarative
configuration.  The camera specific modifications I described in this article
are in a &lt;a href="https://github.com/wagdav/homelab/blob/c69d43d1b192070e3e741f7e7dafdc1fbb1e8c74/modules/camera-rpi-v1/default.nix"&gt;NixOS module&lt;/a&gt; which is included in my Raspberry
Pi&amp;#8217;s &lt;a href="https://github.com/wagdav/homelab/blob/c69d43d1b192070e3e741f7e7dafdc1fbb1e8c74/host-rp3.nix"&gt;host configuration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By choosing NixOS over the official Raspberry Pi &lt;span class="caps"&gt;OS&lt;/span&gt; I set myself up to an
arduous journey.   But, I learned about details of the camera stack, and now I
appreciate more the integration work done by the Raspberry Pi&amp;nbsp;Foundation.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Software Quality</title><link href="https://thewagner.net/blog/2024/06/25/software-quality/" rel="alternate"/><published>2024-06-25T00:00:00+02:00</published><updated>2024-06-25T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2024-06-25:/blog/2024/06/25/software-quality/</id><summary type="html">&lt;p&gt;I was always part of software teams that wanted to write high quality software.
Most team members &lt;em&gt;felt&lt;/em&gt; what was good or bad quality software.  Some goodness
criteria were accepted by everybody in the team, perhaps some remained&amp;nbsp;controversial.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m sure every team had heated discussions about software quality …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I was always part of software teams that wanted to write high quality software.
Most team members &lt;em&gt;felt&lt;/em&gt; what was good or bad quality software.  Some goodness
criteria were accepted by everybody in the team, perhaps some remained&amp;nbsp;controversial.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m sure every team had heated discussions about software quality.  Yet, it&amp;#8217;s
surprisingly hard to find a working definition of it.  In this post I review
the definition of &lt;em&gt;software quality&lt;/em&gt; found in the book &lt;em&gt;Facts and Fallacies of
Software Engineering&lt;/em&gt; by Robert L. Glass from&amp;nbsp;2002.&lt;/p&gt;
&lt;h1&gt;Definition&lt;/h1&gt;
&lt;p&gt;Fact 46 of &lt;em&gt;Facts and Fallacies of Software Engineering&lt;/em&gt; defines software
quality as a collection of the following seven&amp;nbsp;attributes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Reliability&lt;/em&gt; is about a software product that does what it&amp;#8217;s supposed to do,
  and does it&amp;nbsp;dependably.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Usability&lt;/em&gt; is about the ease and comfort of&amp;nbsp;use.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Understandability&lt;/em&gt; is about a software product that is easy for a maintainer
  to&amp;nbsp;comprehend.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Modifiability&lt;/em&gt; is about software that is easy for a maintainer to add new
  capabilities without breaking existing&amp;nbsp;ones.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Efficiency&lt;/em&gt; is about the economy in running time and space&amp;nbsp;consumption.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Testability&lt;/em&gt; is about a software product that is easy to&amp;nbsp;test.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Portability&lt;/em&gt; is about a software product that is easy to move to another&amp;nbsp;platform.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is no general, correct order of these attributes.  The priorities of each
software project are&amp;nbsp;different.&lt;/p&gt;
&lt;h1&gt;Discussion&lt;/h1&gt;
&lt;p&gt;According to Glass, this definition of quality took the test of time, yet it
remains controversial.  Glass warns against attaching unrelated attributes &amp;#8212;
development cost, user satisfaction or delivering on time &amp;#8212; to software
quality.  Of course it&amp;#8217;s desirable if a user receives the software on time and
they are satisfied with it.  This may be due to good customer support and
excellent project management.  User satisfaction is certainly influenced by
software quality, but not defined by&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;The definition of quality is industry specific.  Just like the priority of the
quality attributes is project&amp;nbsp;specific.&lt;/p&gt;
&lt;p&gt;Reliability and efficiency can be measured or estimated, for example, by
monitoring tools.  The other attributes are fuzzy and subjective which makes it
impossible to express quality using &amp;#8220;hard&amp;#8221; metrics.  This is not a problem
because measurement is not invaluable for managing quality.  Humans can manage
research, design and many intellectual and creative things without numbers
guiding them.  Accepting that some attributes remain qualitative is better than
pretending that a chart with made-up data is anyhow&amp;nbsp;relevant.&lt;/p&gt;
&lt;h1&gt;Responsibility&lt;/h1&gt;
&lt;p&gt;Managers are &lt;a href="https://thewagner.net/blog/2023/02/28/managing-the-development-of-large-software-systems/"&gt;responsible for the success of a software
project&lt;/a&gt;.  But quality is not a
management job.  Each of the quality &amp;#8220;-abilities&amp;#8221; have deeply technical
aspects, therefore it is the responsibility of technical team to work towards
the desired quality&amp;nbsp;level.&lt;/p&gt;
&lt;p&gt;Managers do, however, have an important role to establish a culture where
achieving quality is given high priority.  They can hire good engineers and let
them build great&amp;nbsp;software.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Software quality is a collection of seven attributes: reliability, usability,
modifiability, efficiency, testability and portability.  Not all attributes
make sense in all situations so teams should make their own priority list of
these attributes for each project.  Ensuring quality is a technical job.  It&amp;#8217;s
impossible to measure software quality, but this doesn&amp;#8217;t mean it cannot be&amp;nbsp;managed.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>The Stupidity Paradox</title><link href="https://thewagner.net/blog/2024/04/19/the-stupidity-paradox/" rel="alternate"/><published>2024-04-19T00:00:00+02:00</published><updated>2024-04-19T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2024-04-19:/blog/2024/04/19/the-stupidity-paradox/</id><summary type="html">&lt;p&gt;This is a review of the book &lt;em&gt;The Stupidity Paradox&lt;/em&gt; by Mats Alvesson and
André Spicer which explores the role of functional stupidity in contemporary&amp;nbsp;organizations.&lt;/p&gt;
&lt;p&gt;The authors&amp;#8217; thesis is that functional stupidity is omnipresent, especially in
large firms, and it has a mix of positive and negative outcomes.  The …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is a review of the book &lt;em&gt;The Stupidity Paradox&lt;/em&gt; by Mats Alvesson and
André Spicer which explores the role of functional stupidity in contemporary&amp;nbsp;organizations.&lt;/p&gt;
&lt;p&gt;The authors&amp;#8217; thesis is that functional stupidity is omnipresent, especially in
large firms, and it has a mix of positive and negative outcomes.  The paradox
is that presence of stupidity is not always bad, but it can have some&amp;nbsp;benefits.&lt;/p&gt;
&lt;h1&gt;Stupidity&amp;nbsp;Today&lt;/h1&gt;
&lt;p&gt;In the first part of the book the authors claim that predictions from the 1960s
about the arrival of knowledge-based economy still remains a promise.  The
reality is that only a small fraction of jobs are knowledge-intensive.  In
fact, contemporary organizations make many smart people do stupid&amp;nbsp;things.&lt;/p&gt;
&lt;p&gt;Functional stupidity is the absence of reflection on the purpose or the wider
context of a job.  You do the job correctly, focusing on the technical details
but stop searching for questions about the work.  Three aspects characterize
functional&amp;nbsp;stupidity:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Lack of reflexivity&lt;/em&gt;: You don&amp;#8217;t think about your&amp;nbsp;assumptions.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lack of justification&lt;/em&gt;: You don&amp;#8217;t ask why you&amp;#8217;re doing&amp;nbsp;something.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lack of substantive reasoning&lt;/em&gt;: You don&amp;#8217;t consider the consequences or
   wider meaning of your&amp;nbsp;actions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Wishful thinking, following leaders without scrutiny, unreasoning zeal for fads
and fashions, senseless imitation of others and the use of clichés in place of
careful analysis are examples of functional&amp;nbsp;stupidity.&lt;/p&gt;
&lt;p&gt;In organizations a small amount of functional stupidity is beneficial.
Avoiding difficult conversations can help individuals to suppress their doubts,
be happy and feel comfortable with ambiguity.  Ignoring negative impulses help
to get along better with colleagues and provide a steady climb on the corporate&amp;nbsp;ladder.&lt;/p&gt;
&lt;p&gt;But if people stop asking probing questions and ignore problems for too long,
functional stupidity can lead to larger problems and disasters.  People grow
cynical and alienated when they see a large discrepancy between proclaimed
values and actual&amp;nbsp;work.&lt;/p&gt;
&lt;h1&gt;Five kinds of Functional&amp;nbsp;Stupidity&lt;/h1&gt;
&lt;p&gt;The second part of the book explores five sources of functional stupidity which
are common in organizations, induced by leadership, structure, imitation,
branding and&amp;nbsp;culture.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Leadership-induced stupidity&lt;/em&gt;. When people develop an unquestioning faith in
their boss and in the magical powers of&amp;nbsp;leadership.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Structure-induced stupidity&lt;/em&gt;.  Formal processes and structures are required in
organizations but they don&amp;#8217;t guarantee quality, reliability and productivity.
People often blindly trust processes and systems which don&amp;#8217;t produce the
results they hope for.  The mixture of senior managers who mainly sit in
meetings talking to other managers, narrowly focused experts, and routinized
workers create organizations where rule-following trumps good&amp;nbsp;results.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Imitation-induced stupidity&lt;/em&gt;.  Managers often adopt structures and formal
practices that look good and not what makes the organization function more
efficiently.  This is to create an image which conforms to broadly shared
expectations of how an organization should be.  But a disconnect between the
organization&amp;#8217;s image and its everyday practices lead to frustration, low
commitment and&amp;nbsp;cynicism.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Branding-induced stupidity&lt;/em&gt;.  There is a massive overproduction in many parts
of the economy.  To dispose of this surplus we developed an economy of
persuasion.  Branding helps to transform the dull job of convincing people
about things they don&amp;#8217;t need or want into something that sounds exciting and
interesting.  But branding activities are often met with indifference and&amp;nbsp;cynicism.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Culture-induced stupidity&lt;/em&gt;.  Corporate culture coordinates people, offers a
shared sense of purpose, creates a common identity and reduces conflicts and
confusion.  But culture always includes a degree of functional stupidity.  Most
organizations foster a culture of optimism, focusing on the present and being
change oriented.  But when you can&amp;#8217;t mention bad news you often can&amp;#8217;t adapt to
important changes.  If you don&amp;#8217;t look at the past you cannot learn from it. And
an organization that drifts from one change initiative to another without real
benefits becomes self-obsessed and gets harder to get actual work&amp;nbsp;done.&lt;/p&gt;
&lt;h1&gt;Stupidity&amp;nbsp;management&lt;/h1&gt;
&lt;p&gt;Although it&amp;#8217;s never presented explicitly, stupidity management, that is to
reduce thinking at work, is an important activity for managers. Again, small
amount of functional stupidity can be advantageous because too much thinking
can lead to conflicts, uncertainties, doubts and reduced&amp;nbsp;motivation.&lt;/p&gt;
&lt;p&gt;The third part enumerates four ways managers encourage functional&amp;nbsp;stupidity:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Authority&lt;/em&gt;: Manager use their formal position in the hierarchy to make
  subordinates follow polices and orders.  The hope for a reward or the fear of
  punishment discourages staff from thinking too&amp;nbsp;much.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Seduction&lt;/em&gt;: Managers enlist attractive ideas and arrangements to persuade
  people. It&amp;#8217;s often about arguing that change is always good and about
  painting a rosy picture of the future absent of the past and present&amp;nbsp;problems.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Naturalisation&lt;/em&gt;: Managers claim that the organization&amp;#8217;s assumptions, its
  view of the word, and goals are self-evident, or&amp;nbsp;natural.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Opportunism&lt;/em&gt;: Managers buy into questionable trends or actions because good
  things will follow.  Instead of searching or explaining the purpose of an
  action they rationalize the&amp;nbsp;doubts.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The closing chapter proposes to fight functional stupidity with &lt;em&gt;critical
thinking&lt;/em&gt;: querying assumptions, asking for and being prepared to give
justification and considering the outcomes and meaning of what we&amp;nbsp;do.&lt;/p&gt;
&lt;p&gt;The authors suggest that organizations instead of encouraging only optimism
they should build up &lt;em&gt;negative capability&lt;/em&gt;, the ability to face uncertainty,
paradoxes and ambiguities.  Some steps in this directions&amp;nbsp;are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Post- or pre-mortems&lt;/em&gt;: Take a good look at a failed project and learn from
  it.  Or, before a project starts try to imagine all possible ways the project
  could&amp;nbsp;fail.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Listening to newcomers and outsiders&lt;/em&gt;: New employees or an external person
  may point out deficiencies or silly things in your organization that you&amp;#8217;ve
  grown accustomed&amp;nbsp;to.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Reflective routines and anti-stupidity task force&lt;/em&gt;: Regularly stop to think
  and ask: &lt;em&gt;Why?&lt;/em&gt;.  Evaluate your projects, structures and processes. Do they
  make sense? What&amp;#8217;s their purpose? Perhaps even try to discontinue or cancel
  an activity or an&amp;nbsp;arrangement.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I&amp;#8217;d recommend &lt;em&gt;The Stupidity Paradox&lt;/em&gt; to everybody who works for any
organization that employs more than a dozen people.  Functional stupidity &amp;#8212;
characterized by the lack of reflexivity,  lack of justification and the lack
of substantive reasoning &amp;#8212; is everywhere in today&amp;#8217;s organizations.  This
sounds depressing.  Indeed, even the authors are&amp;nbsp;concerned:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Everyone from CEOs to low-level employees is regularly put at risk of
overdosing on stupidity management.  We believe  that this corporate no-think
is one of the most urgent, yet most challenging, issues that organizations
face&amp;nbsp;today.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But the book also makes the point that inhibiting individual thinking in
certain cases results in less conflicts, happier work environment and higher&amp;nbsp;productivity.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The Stupidity Paradox&lt;/em&gt; helps to spot elements of functional stupidity and
provides some advise how to keep it under control.  In summary, the antidote of
functional stupidity is critical thinking: reflecting on your assumptions, on
your actions and on their&amp;nbsp;consequences.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Year 2023 in review</title><link href="https://thewagner.net/blog/2023/12/31/year-2023-in-review/" rel="alternate"/><published>2023-12-31T00:00:00+01:00</published><updated>2023-12-31T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2023-12-31:/blog/2023/12/31/year-2023-in-review/</id><summary type="html">&lt;p&gt;This post is a short summary of the articles I wrote in&amp;nbsp;2023.&lt;/p&gt;
&lt;p&gt;At the beginning of the year reviewed Winston Royce&amp;#8217;s 1970 paper on &lt;a href="https://thewagner.net/blog/2023/02/28/managing-the-development-of-large-software-systems/"&gt;Managing
the development of large software systems&lt;/a&gt;.  This paper is list of
suggestions about what makes a software project succeed.  Perhaps at places the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This post is a short summary of the articles I wrote in&amp;nbsp;2023.&lt;/p&gt;
&lt;p&gt;At the beginning of the year reviewed Winston Royce&amp;#8217;s 1970 paper on &lt;a href="https://thewagner.net/blog/2023/02/28/managing-the-development-of-large-software-systems/"&gt;Managing
the development of large software systems&lt;/a&gt;.  This paper is list of
suggestions about what makes a software project succeed.  Perhaps at places the
language is archaic, but most of Royce&amp;#8217;s observations still apply&amp;nbsp;today.&lt;/p&gt;
&lt;p&gt;I spent a few hours every month to improve my &lt;a href="https://github.com/wagdav/homelab"&gt;Homelab&lt;/a&gt;.  I
started hacking on some spare computers at home &lt;a href="https://github.com/wagdav/homelab/commit/8c697472504f92e34e93dc8d58a3dea309d5b6b6"&gt;in 2019&lt;/a&gt;,
because I was interested in configuration management systems such as Ansible,
Salt and Puppet.  Then, I discovered &lt;a href="https://thewagner.net/blog/2020/04/30/exploring-nix/"&gt;Nix&lt;/a&gt; which became the most important
tool to build all my projects and to configure my&amp;nbsp;servers.&lt;/p&gt;
&lt;p&gt;This year I configured &lt;a href="https://thewagner.net/blog/2023/11/25/homelab-deployment/"&gt;automatic deployment&lt;/a&gt; for all my servers at
home.  This includes a &lt;a href="https://thewagner.net/blog/2023/11/20/building-nix-packages-for-the-raspberry-pi-with-github-actions/"&gt;Raspberry Pi&lt;/a&gt; for which building software using
freely available build servers such as GitHub Actions is&amp;nbsp;non-trivial.&lt;/p&gt;
&lt;p&gt;Finally, as in the past few years, in December I spent my free time solving the
&lt;a href="https://thewagner.net/blog/2023/12/25/advent-of-code-2023/"&gt;Advent of Code&lt;/a&gt;&amp;nbsp;puzzles.&lt;/p&gt;
&lt;p&gt;Thanks for reading and happy&amp;nbsp;2024!&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Advent of Code 2023</title><link href="https://thewagner.net/blog/2023/12/25/advent-of-code-2023/" rel="alternate"/><published>2023-12-25T00:00:00+01:00</published><updated>2023-12-25T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2023-12-25:/blog/2023/12/25/advent-of-code-2023/</id><summary type="html">&lt;p&gt;Solving the Advent of Code 2023 puzzles in&amp;nbsp;Clojure.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Since 2020, every year I solve the &lt;a href="https://adventofcode.com/"&gt;Advent of Code&lt;/a&gt;
puzzles.  This post, like &lt;a href="https://thewagner.net/blog/2020/12/25/advent-of-code-2020/"&gt;those&lt;/a&gt; of &lt;a href="https://thewagner.net/blog/2021/12/25/advent-of-code-2021/"&gt;previous&lt;/a&gt;
&lt;a href="https://thewagner.net/blog/2022/12/25/advent-of-code-2022/"&gt;years&lt;/a&gt;, is an experience report of my 25+ day journey in&amp;nbsp;December.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: If you&amp;#8217;re still working or planning to work on the puzzles
stop reading&amp;nbsp;now.&lt;/p&gt;
&lt;h1&gt;Puzzles&lt;/h1&gt;
&lt;p&gt;Between December 1 and December 25, a programming puzzle appears every day on
the Advent of Code website.  Each problem has two parts, the second part
unlocks after you complete the first.  To understand each day&amp;#8217;s puzzle, go to
the website and read the full description (for example &lt;a href="https://adventofcode.com/2023/day/1"&gt;Day 1:
Trebuchet?!&lt;/a&gt;).&lt;/p&gt;
&lt;h1&gt;Setup&lt;/h1&gt;
&lt;p&gt;This year again, now the third time, I wrote my solutions in Clojure.  Every
year I understand more of the standard library and I feel I write more
concise and more idiomatic code than in the previous&amp;nbsp;years.&lt;/p&gt;
&lt;p&gt;Usually I solved the day&amp;#8217;s problem before going to work, sometimes I coded a
bit in the evening to polish my&amp;nbsp;solution.&lt;/p&gt;
&lt;p&gt;My &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day14.clj"&gt;Day 14&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day22.clj"&gt;Day 22&lt;/a&gt; solutions are slow: they run for about a
hundred seconds to find the solution.  I suspect that these programs would be
more efficient if I wrote them as a loop updating some local mutable state.
Next year, I want to study profiling and optimizing Clojure&amp;nbsp;code.&lt;/p&gt;
&lt;h1&gt;Highlights&lt;/h1&gt;
&lt;p&gt;On &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day12.clj"&gt;Day 12&lt;/a&gt; I was proud to find a recursive solution using dynamic
programming.  In previous years,  for example &lt;a href="https://adventofcode.com/2020/day/10"&gt;Day 10 in
2020&lt;/a&gt;, I struggled with similar&amp;nbsp;problems.&lt;/p&gt;
&lt;p&gt;I solved &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day14.clj"&gt;Day 14&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day20.clj"&gt;Day 20&lt;/a&gt; by finding cycles in a periodic
solution.  This is also something I was more comfortable this year than&amp;nbsp;before.&lt;/p&gt;
&lt;p&gt;It was difficult to wrap my head around the interval arithmetics required to
solve &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day05.clj"&gt;Day 5&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day19.clj"&gt;Day 19&lt;/a&gt;.  Finally, I brute forced Day 5 and
put aside the second part of Day 19 for a few&amp;nbsp;days.&lt;/p&gt;
&lt;p&gt;The second parts of &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day18.clj"&gt;Day 18&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day21.clj"&gt;Day 21&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day23.clj"&gt;Day 23&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day24.clj"&gt;Day
24&lt;/a&gt; were the hardest to crack.  I couldn&amp;#8217;t solve these problems on my
own and I used some help from &lt;a href="https://www.reddit.com/r/adventofcode/"&gt;Reddit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On &lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day18.clj"&gt;Day 18&lt;/a&gt; I was on the right track, but I didn&amp;#8217;t figure out how to
apply &lt;a href="https://en.wikipedia.org/wiki/Pick%27s_theorem"&gt;Pick&amp;#8217;s theorem&lt;/a&gt; to find
the&amp;nbsp;solution.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day21.clj"&gt;Day 21&lt;/a&gt; was just too hard for me: I had some ideas, but nothing worked.
I failed to recognize the hidden patterns in the input data. A typical Advent
of Code&amp;nbsp;puzzle.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day23.clj"&gt;Day 23&lt;/a&gt; asked to find the longest path in a labyrinth. This is, as I
learned this year, a much harder problem than finding the shortest path.  I
understood how to reduce the size of the search space, but my code is messy
and I made a lot of mistakes during the&amp;nbsp;implementation.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day24.clj"&gt;Day 24&lt;/a&gt; was about line intersections.  I understand well the underlying
mathematical models but I failed to find a set of linear equations that yielded
the solution.  During the fourth week, I was tired and impatient to do symbolic&amp;nbsp;math.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/wagdav/advent-of-code-2023/blob/main/src/aoc2023/day25.clj"&gt;Day 25&lt;/a&gt; asked to remove three vertices from a graph to create two
isolated groups of nodes.  Instead of writing code, I solved this problem
graphically: I visualized the graph with the &lt;a href="https://graphviz.org/"&gt;Graphviz&lt;/a&gt;
and manually selected the nodes to&amp;nbsp;remove.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;2023 Advent of Code started well and I had a few small victories on some harder
days.  The second parts of Day 18, Day 21, Day 23 and Day 24 were too hard for
me and I used external help.  As always, on these tough days I learned the&amp;nbsp;most.&lt;/p&gt;
&lt;p&gt;As usual, after solving the puzzles I like to see how others approached the
same problem.  Here are some repositories I regularly&amp;nbsp;checked:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/KornelJahn/advent-of-code-2023"&gt;Jahn Kornél&amp;nbsp;(Python)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jonathanpaulson/AdventOfCode/tree/master/2023"&gt;Jonathan Paulson&amp;nbsp;(Python)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/odormond/adventofcode/tree/master/2023"&gt;Olivier Dormond&amp;nbsp;(Python)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My solutions are available on &lt;a href="https://github.com/wagdav/advent-of-code-2023"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Acknowledgments&lt;/h1&gt;
&lt;p&gt;Thanks &lt;a href="https://twitter.com/ericwastl"&gt;Eric Wastl&lt;/a&gt; for creating and running
&lt;a href="https://adventofcode.com"&gt;Advent of Code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I enjoyed exchanging ideas and analyzing solutions with my friend
&lt;a href="https://github.com/KornelJahn/"&gt;Kornél&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Homelab deployment</title><link href="https://thewagner.net/blog/2023/11/25/homelab-deployment/" rel="alternate"/><published>2023-11-25T00:00:00+01:00</published><updated>2023-11-25T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2023-11-25:/blog/2023/11/25/homelab-deployment/</id><summary type="html">&lt;p&gt;I configured continuous deployment in &lt;a href="https://thewagner.net/blog/2020/05/31/homelab/"&gt;my homelab&lt;/a&gt;. This article
describes how I use Nix with GitHub Actions and Cachix Deploy to automatically
deploy NixOS machines on my home&amp;nbsp;network.&lt;/p&gt;
&lt;h1&gt;Overview&lt;/h1&gt;
&lt;p&gt;My home network comprises a wireless router, a few computers, temperature and
humidity sensors and remote controllable switches.  I configure …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I configured continuous deployment in &lt;a href="https://thewagner.net/blog/2020/05/31/homelab/"&gt;my homelab&lt;/a&gt;. This article
describes how I use Nix with GitHub Actions and Cachix Deploy to automatically
deploy NixOS machines on my home&amp;nbsp;network.&lt;/p&gt;
&lt;h1&gt;Overview&lt;/h1&gt;
&lt;p&gt;My home network comprises a wireless router, a few computers, temperature and
humidity sensors and remote controllable switches.  I configure these devices
mainly using Nix, and when it&amp;#8217;s possible, I run NixOS on them.  I use this
setup to experiment with &lt;a href="https://thewagner.net/blog/2020/05/31/homelab/"&gt;home automation and to learn about new
tools&lt;/a&gt;. The entire configuration of my home network is &lt;a href="https://github.com/wagdav/homelab"&gt;available on
GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The configuration of the NixOS servers was always built from a declarative
specification stored in version control system. But the deployment of the new
configuration was manual, slow and often tedious.  I&amp;nbsp;ran &lt;code&gt;nixos-build&lt;/code&gt; from the
command line, and sometimes I had to wait an hour to build and deploy the new
machine&amp;nbsp;configuration.&lt;/p&gt;
&lt;p&gt;I wanted to reconfigure my servers automatically, triggered by committing to a
Git&amp;nbsp;repository.&lt;/p&gt;
&lt;p&gt;To solve this problem I built a system based on Nix and freely available hosted&amp;nbsp;services:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure1" src="https://thewagner.net/images/homelab-deployment.svg" title="Homelab deployment"&gt;&lt;/p&gt;
&lt;p&gt;The automatic deployments work as&amp;nbsp;follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;a href="https://github.com/wagdav/homelab"&gt;Homelab repository&lt;/a&gt; contains the NixOS host&amp;nbsp;configurations.&lt;/li&gt;
&lt;li&gt;A workflow in &lt;a href="https://github.com/wagdav/homelab/blob/master/.github/workflows/build-and-deploy.yml"&gt;GitHub Action&lt;/a&gt; &lt;em&gt;builds&lt;/em&gt; the NixOS system and
   &lt;em&gt;stores&lt;/em&gt; it in a &lt;a href="https://www.cachix.org/"&gt;hosted binary cache&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An agent on the target machine &lt;em&gt;pulls&lt;/em&gt; the built binaries from the cache and
   &lt;em&gt;activates&lt;/em&gt; the new&amp;nbsp;deployment.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Host&amp;nbsp;configuration&lt;/h1&gt;
&lt;p&gt;The configuration of my servers is written in the Nix language.  For example,
&lt;a href="https://github.com/wagdav/homelab/blob/master/host-nuc.nix"&gt;host-nuc.nix&lt;/a&gt; describes the hardware and software configuration of
my Intel &lt;span class="caps"&gt;NUC&lt;/span&gt;&amp;nbsp;device:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; config&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;imports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="l"&gt;./hardware/nuc.nix&lt;/span&gt;
    &lt;span class="l"&gt;./modules/cachix.nix&lt;/span&gt;
    &lt;span class="l"&gt;./modules/common.nix&lt;/span&gt;
    &lt;span class="l"&gt;./modules/consul/server.nix&lt;/span&gt;
    &lt;span class="l"&gt;./modules/git.nix&lt;/span&gt;
    &lt;span class="l"&gt;./modules/grafana&lt;/span&gt;
    &lt;span class="l"&gt;./modules/loki.nix&lt;/span&gt;
    &lt;span class="l"&gt;./modules/mqtt.nix&lt;/span&gt;
    &lt;span class="l"&gt;./modules/prometheus.nix&lt;/span&gt;
    &lt;span class="l"&gt;./modules/push-notifications.nix&lt;/span&gt;
    &lt;span class="l"&gt;./modules/remote-builder&lt;/span&gt;
    &lt;span class="l"&gt;./modules/traefik.nix&lt;/span&gt;
    &lt;span class="l"&gt;./modules/vpn.nix&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  system&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;stateVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;22.05&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The configuration is split into modules.  Glancing at&amp;nbsp;the &lt;code&gt;imports&lt;/code&gt; block you
can tell what is installed on this machine.  The&amp;nbsp;host &lt;code&gt;nuc&lt;/code&gt; is my main home
server, it runs all my &amp;#8220;production&amp;#8221;&amp;nbsp;services.&lt;/p&gt;
&lt;p&gt;For example,&amp;nbsp;the &lt;code&gt;cachix.nix&lt;/code&gt; module configures the &lt;a href="https://docs.cachix.org/deploy/running-an-agent/"&gt;Cachix
Agent&lt;/a&gt; which is responsible
for reconfiguring the NixOS machine when a new build is available.  The agent
runs on all machines whose configuration automatically&amp;nbsp;managed.&lt;/p&gt;
&lt;h1&gt;Building with GitHub&amp;nbsp;Actions&lt;/h1&gt;
&lt;p&gt;The NixOS host specifications are built with a&amp;nbsp;single &lt;code&gt;nix build&lt;/code&gt; command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nix build .#nixosConfigurations.nuc.config.system.build.toplevel
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This builds the whole system for&amp;nbsp;the &lt;code&gt;nuc&lt;/code&gt; machine: the kernel, the installed
packages and their configuration.  By&amp;nbsp;default, &lt;code&gt;nix&lt;/code&gt; downloads pre-built
packages from the &lt;a href="http://cache.nixos.org/"&gt;NixOS public binary cache&lt;/a&gt;, so a
typical execution of the build command takes only a few&amp;nbsp;minutes.&lt;/p&gt;
&lt;p&gt;To run the build in GitHub Actions, the build job installs Nix and configures
the access to the Cachix binary cache where the deployment artifacts are&amp;nbsp;stored:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;ubuntu-latest&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;Homelab&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://app.cachix.org/deploy/workspace/lab.thewagner.home/&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# ⑴&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;actions/checkout@v4&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;docker/setup-qemu-action@v3&lt;/span&gt;&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="c1"&gt;# ⑵&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;cachix/install-nix-action@v23&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;extra_nix_config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;extra-platforms&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;aarch64-linux&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;# ⑶&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;cachix/cachix-action@v12&lt;/span&gt;&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;# ⑷&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;wagdav&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;authToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.CACHIX_AUTH_TOKEN&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;nix build --print-build-logs .#cachix-deploy-spec&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# ⑸&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;&lt;span class="w"&gt;                                                            &lt;/span&gt;&lt;span class="c1"&gt;# ⑹&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="no"&gt;cachix push wagdav ./result&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="no"&gt;cachix deploy activate --async ./result&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;CACHIX_ACTIVATE_TOKEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.CACHIX_ACTIVATE_TOKEN&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;build&lt;/code&gt; job of the &lt;a href="https://github.com/wagdav/homelab/blob/master/.github/workflows/build-and-deploy.yml"&gt;workflow&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Configures a &lt;a href="https://docs.github.com/en/actions/deployment/about-deployments/deploying-with-github-actions#using-environments"&gt;deployment target&lt;/a&gt;. When a GitHub Actions
   workflow deploys to an environment, the environment is displayed on the main
   page of the&amp;nbsp;repository.&lt;/li&gt;
&lt;li&gt;Installs the &lt;span class="caps"&gt;QEMU&lt;/span&gt; static binaries for building packages for architectures
   different than that of the build&amp;nbsp;runner.&lt;/li&gt;
&lt;li&gt;Configures Nix to use emulation to &lt;a href="https://thewagner.net/blog/2023/11/20/building-nix-packages-for-the-raspberry-pi-with-github-actions/"&gt;build &lt;span class="caps"&gt;ARM&lt;/span&gt; 64 packages&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Configures the &lt;a href="https://cachix.org"&gt;Cachix hosted binary cache&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Builds the &lt;a href="https://docs.cachix.org/deploy/deploying-to-agents/#write-deploy-specification"&gt;deploy specification&lt;/a&gt; which is a set of the NixOS
   systems to&amp;nbsp;deploy.&lt;/li&gt;
&lt;li&gt;Pushes the built binaries to the cache and sends an activation signal to the
   Cachix&amp;nbsp;Agent.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The job uses two&amp;nbsp;secrets: &lt;code&gt;CACHIX_AUTH_TOKEN&lt;/code&gt; is the authentication token to
push to the binary cache&amp;nbsp;and &lt;code&gt;CACHIX_ACTIVATE_TOKEN&lt;/code&gt; is required to activate
the built NixOS&amp;nbsp;configurations.&lt;/p&gt;
&lt;h1&gt;Deploying with Cachix&amp;nbsp;Deploy&lt;/h1&gt;
&lt;p&gt;To deploy the built NixOS configurations I use the generous free-tier of
&lt;a href="https://docs.cachix.org/deploy/"&gt;Cachix Deploy&lt;/a&gt;.  Following their
documentation, I&amp;nbsp;installed &lt;code&gt;cachix-agent&lt;/code&gt; on the target hosts and configured a
few authentication&amp;nbsp;keys.&lt;/p&gt;
&lt;p&gt;The agent process connects to the Cachix backend and waits for a deployment.
When a new deployment is available, the agent pulls the relevant binaries from
the binary cache and reconfigures the NixOS system it runs&amp;nbsp;on.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Since I configured &lt;a href="https://thewagner.net/blog/2020/12/06/deploying-with-github-actions-and-more-nix/"&gt;automatic deployment of this blog&lt;/a&gt; I wanted
the same for my home infrastructure.  I had my configuration repository and I
knew how to build the machine configurations with GitHub Actions.  I was
missing the automatic deployment part until Cachix Deploy was announced.
Cachix has excellent documentation and the integration with my Homelab was
super&amp;nbsp;simple.&lt;/p&gt;
&lt;h1&gt;Acknowledgement&lt;/h1&gt;
&lt;p&gt;I&amp;#8217;m grateful to &lt;a href="https://www.cachix.org/"&gt;Cachix Deploy&lt;/a&gt; for offering a binary
cache and a deployment&amp;nbsp;service.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Building Nix packages for the Raspberry Pi with GitHub Actions</title><link href="https://thewagner.net/blog/2023/11/20/building-nix-packages-for-the-raspberry-pi-with-github-actions/" rel="alternate"/><published>2023-11-20T00:00:00+01:00</published><updated>2023-11-20T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2023-11-20:/blog/2023/11/20/building-nix-packages-for-the-raspberry-pi-with-github-actions/</id><summary type="html">&lt;p&gt;Building Nix packages for the Raspberry Pi 3 or newer requires building for an
&lt;span class="caps"&gt;ARM&lt;/span&gt; 64 architecture, which Nix refers to&amp;nbsp;as &lt;code&gt;aarch64-linux&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To&amp;nbsp;build &lt;code&gt;aarch64-linux&lt;/code&gt; binaries we&amp;nbsp;can:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build natively on&amp;nbsp;an &lt;code&gt;aarch64-linux&lt;/code&gt; machine.&lt;/li&gt;
&lt;li&gt;Cross compile&amp;nbsp;for &lt;code&gt;aarch64-linux&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Compile with an&amp;nbsp;emulator.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first option is the simplest.  For …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Building Nix packages for the Raspberry Pi 3 or newer requires building for an
&lt;span class="caps"&gt;ARM&lt;/span&gt; 64 architecture, which Nix refers to&amp;nbsp;as &lt;code&gt;aarch64-linux&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To&amp;nbsp;build &lt;code&gt;aarch64-linux&lt;/code&gt; binaries we&amp;nbsp;can:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build natively on&amp;nbsp;an &lt;code&gt;aarch64-linux&lt;/code&gt; machine.&lt;/li&gt;
&lt;li&gt;Cross compile&amp;nbsp;for &lt;code&gt;aarch64-linux&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Compile with an&amp;nbsp;emulator.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first option is the simplest.  For example, a Raspberry Pi with Nix
installed compiles&amp;nbsp;the &lt;code&gt;aarch64-linux&lt;/code&gt; binaries reasonably well. Typically, you
need to build only a few packages from source and the rest may be downloaded
from the &lt;a href="https://cache.nixos.org"&gt;Nix public binary cache&lt;/a&gt;.  You can also use
a more powerful &lt;span class="caps"&gt;ARM&lt;/span&gt; 64 computer for building, if you own or rent&amp;nbsp;one.&lt;/p&gt;
&lt;p&gt;I have little to say about the second option because I never managed to get it
working.  I also suspect that cross compiled packages are not in the public
binary cache, so build times are longer than native&amp;nbsp;builds.&lt;/p&gt;
&lt;p&gt;In the rest of the article I explore the third option: compiling with an
emulator, in particular with &lt;span class="caps"&gt;QEMU&lt;/span&gt;.&lt;/p&gt;
&lt;h1&gt;On&amp;nbsp;NixOS&lt;/h1&gt;
&lt;p&gt;On NixOS, it&amp;#8217;s trivial to use &lt;span class="caps"&gt;QEMU&lt;/span&gt; to build for different architectures.  You
need to &lt;a href="https://nixos.org/manual/nixos/stable/options#opt-boot.binfmt.emulatedSystems"&gt;adjust one parameter&lt;/a&gt; in your NixOS host&amp;nbsp;configuration:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;boot&lt;span class="o"&gt;.&lt;/span&gt;binfmt&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;emulatedSystems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;aarch64-linux&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This snippet installs and configures &lt;span class="caps"&gt;QEMU&lt;/span&gt; and enables emulated builds for the
Raspberry Pi.  For example, to build
&lt;a href="https://www.gnu.org/software/hello/"&gt;hello&lt;/a&gt; from source,&amp;nbsp;run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nix build nixpkgs#legacyPackages.aarch64-linux.hello --no-substitute
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For this demonstration I added&amp;nbsp;the &lt;code&gt;--no-substitute&lt;/code&gt; flag to disallow binary
substitutes.  In other words, this flag forces Nix to build all packages from&amp;nbsp;source.&lt;/p&gt;
&lt;p&gt;If the compilation with the emulated tool chain works, Nix writes an &lt;span class="caps"&gt;ARM&lt;/span&gt; 64-bit
binary&amp;nbsp;at &lt;code&gt;./result/bin/hello&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;Using GitHub&amp;nbsp;Actions&lt;/h1&gt;
&lt;p&gt;Recently I discovered the &lt;a href="https://github.com/marketplace/actions/docker-setup-qemu"&gt;setup-qemu-action&lt;/a&gt; from Docker which
helps us to configure a hosted GitHub Action runner to build for the Raspberry&amp;nbsp;Pi:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;ubuntu-latest&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;actions/checkout@v4&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;docker/setup-qemu-action@v3&lt;/span&gt;&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="c1"&gt;# ⑴&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;cachix/install-nix-action@v23&lt;/span&gt;&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="c1"&gt;# ⑵&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;extra_nix_config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;extra-platforms&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;aarch64-linux&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;-run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;&lt;span class="w"&gt;                                                                 &lt;/span&gt;&lt;span class="c1"&gt;# ⑶&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;nix build nixpkgs#legacyPackages.aarch64-linux.hello --no-substitute&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This GitHub Actions workflow starts an Ubuntu virtual machine and installs&amp;nbsp;Nix:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the &lt;span class="caps"&gt;QEMU&lt;/span&gt; static binaries using a &lt;a href="https://github.com/marketplace/actions/docker-setup-qemu"&gt;GitHub Action from
   Docker&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install Nix using a &lt;a href="https://github.com/cachix/install-nix-action"&gt;GitHub Action from Cachix&lt;/a&gt; and configure it
   to allow building&amp;nbsp;for &lt;code&gt;aarch64-linux&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Build &lt;code&gt;hello&lt;/code&gt; for &lt;code&gt;aarch64-linux&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Using two GitHub Actions from &lt;a href="https://github.com/marketplace/actions/docker-setup-qemu"&gt;Docker&lt;/a&gt; and &lt;a href="https://github.com/cachix/install-nix-action"&gt;Cachix&lt;/a&gt; I
set up a workflow to build packages for the Raspberry Pi using freely available
Ubuntu runners from&amp;nbsp;GitHub.&lt;/p&gt;
&lt;p&gt;In a &lt;a href="https://thewagner.net/blog/2023/11/25/homelab-deployment/"&gt;related article&lt;/a&gt; I explain how I use this technique to
build and deploy NixOS on Raspberry&amp;nbsp;Pi.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Managing the development of large software systems</title><link href="https://thewagner.net/blog/2023/02/28/managing-the-development-of-large-software-systems/" rel="alternate"/><published>2023-02-28T00:00:00+01:00</published><updated>2023-02-28T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2023-02-28:/blog/2023/02/28/managing-the-development-of-large-software-systems/</id><summary type="html">&lt;p&gt;This is a review of the paper &lt;a href="http://www-scf.usc.edu/~csci201/lectures/Lecture11/royce1970.pdf"&gt;Managing the development of large systems by
Winston W. Royce&lt;/a&gt;, originally published in August&amp;nbsp;1970.&lt;/p&gt;
&lt;p&gt;Figure 2 of this paper often cited as the &lt;a href="https://en.wikipedia.org/wiki/Waterfall_model"&gt;&amp;#8220;waterfall&amp;#8221; method&lt;/a&gt;,
a model that considers the project&amp;#8217;s activities as a linear sequence of steps.
In fact, this …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is a review of the paper &lt;a href="http://www-scf.usc.edu/~csci201/lectures/Lecture11/royce1970.pdf"&gt;Managing the development of large systems by
Winston W. Royce&lt;/a&gt;, originally published in August&amp;nbsp;1970.&lt;/p&gt;
&lt;p&gt;Figure 2 of this paper often cited as the &lt;a href="https://en.wikipedia.org/wiki/Waterfall_model"&gt;&amp;#8220;waterfall&amp;#8221; method&lt;/a&gt;,
a model that considers the project&amp;#8217;s activities as a linear sequence of steps.
In fact, this figure is only the starting point of the paper.  Royce acknowledges
that the depicted model &lt;em&gt;doesn&amp;#8217;t work&lt;/em&gt; in practice and he suggests five
concrete steps that are required for large software projects to&amp;nbsp;succeed.&lt;/p&gt;
&lt;h1&gt;Analysis and&amp;nbsp;coding&lt;/h1&gt;
&lt;p&gt;The paper starts with the observation that there are two essential steps common
to all computer program development: analysis and&amp;nbsp;coding.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure1" src="https://thewagner.net/images/royce1970-figure1.png" title="Figure 1. Implementation steps to deliver a small computer program for internal operations."&gt;&lt;/p&gt;
&lt;p&gt;The author doesn&amp;#8217;t discuss these steps in detail.  I understand the first step
as analysis of the problem at hand and the second as the activity spent typing
in the code, debugging, and deploying.  In other words, first we define what
the desired program is indented to do, then we implement&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Royce claims that this simple, two-step development model works for systems
where the final product is operated by the those who built it.  The rest of the
paper extends this model to explain the development of larger&amp;nbsp;systems:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;#8221;[&amp;#8230;] to manufacture larger software systems [&amp;#8230;] additional development
steps are required, none contribute as directly to the final product as
analysis and coding, and all drive up the development&amp;nbsp;costs.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We will see later that by &lt;em&gt;additional development steps&lt;/em&gt; the author means
program design, defining requirements, writing documentation and testing.  It
seems that in already in 1970 many people didn&amp;#8217;t understand that a software
project is much more than just&amp;nbsp;coding:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;Customer personnel typically would rather not pay for them [the additional
steps], and development personnel would rather not implement them.  The prime
function of management is to sell these concepts to both&amp;nbsp;groups.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nevertheless, Royce holds the management responsible to explain the structure
of the project and the purpose of each step in&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;The author managed the &lt;em&gt;&amp;#8220;development of software packages for spacecraft
mission planning, commanding and post-flight analysis&amp;#8221;&lt;/em&gt;.  Drawn from the
author&amp;#8217;s experience, the paper proposes a development model that is required,
but not sufficient, for such software project to&amp;nbsp;succeed.&lt;/p&gt;
&lt;p&gt;In the sixties the most expensive and most complex software projects solved
scientific and engineering problems, often using hardware with constrained
resources.  Royce clearly makes his claims in this specific context, so perhaps
it&amp;#8217;s foolish to extrapolate to the development of &lt;em&gt;any&lt;/em&gt; software&amp;nbsp;project.&lt;/p&gt;
&lt;h1&gt;Not&amp;nbsp;waterfall&lt;/h1&gt;
&lt;p&gt;The third paragraph introduces the &amp;#8220;additional steps&amp;#8221; the author hinted in the&amp;nbsp;introduction:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;A more grandiose approach to software development is illustrated in Figure
2.  The analysis and coding steps are still in the picture, but they are
preceded by two levels of requirements analysis, are separated by a program
design step, and followed by a testing&amp;nbsp;step.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="Figure2" src="https://thewagner.net/images/royce1970-figure2c.png" title="Figure 2. Implementation steps to develop a large computer program for delivery to a customer."&gt;&lt;/p&gt;
&lt;p&gt;Looking from the manager&amp;#8217;s perspective, Royce&amp;nbsp;continues:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;These additions are treated separately from analysis and coding because
they are distinctly different in the way they are executed. They must be
planned and staffed differently for best utilization of program&amp;nbsp;resources.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The nature of the work in these steps is different, so it makes sense to think
about them separately.  Royce doesn&amp;#8217;t specify how these steps are executed.  In
fact, he doesn&amp;#8217;t discuss this figure any further because this is just an
intermediate step, and he&amp;#8217;s not finished presenting his model&amp;nbsp;yet.&lt;/p&gt;
&lt;h1&gt;Local iterations are&amp;nbsp;insufficient&lt;/h1&gt;
&lt;p&gt;In Figure 3, Royce shows an iterative relationship between successive
development&amp;nbsp;steps.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure3" src="https://thewagner.net/images/royce1970-figure3c.png" title="Hopefully, the iterative interactions between the various phases is confined to successive steps."&gt;&lt;/p&gt;
&lt;p&gt;Royce believes in this approach.  He thinks these small, local iterations have
value&amp;nbsp;because:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;#8221;[&amp;#8230;] as each step progresses and the design is further detailed [&amp;#8230;] The
virtue of all of this is that as the design proceeds the change process is
scoped down to manageable&amp;nbsp;limits.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Adapting the design in small chunks has benefits, but he immediately points out
that following this process is &lt;em&gt;&amp;#8220;risky and invites failure&amp;#8221;&lt;/em&gt;.  The problem is
that iterations only occur between preceding and succeeding steps but rarely in
more remote steps in the sequence.  Royce gives an&amp;nbsp;example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;The testing phase which occurs at the end of the development cycle is the
first event for which timing, storage, input/output transfers, etc., are
experienced as distinguished from analyzed. [&amp;#8230;] if these phenomena fail to
satisfy the various external constraints, then invariably a major redesign is&amp;nbsp;required.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With local iterations only, fundamental design problems surface too late in the
project.  In effect, the development costs increase and the project runs&amp;nbsp;late.&lt;/p&gt;
&lt;p&gt;Before discussing the mitigations, Royce closes this section with a note on the
role of&amp;nbsp;coding:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;One might note that there has been a skipping-over of the analysis and code
phases.  One cannot, of course, produce software without these steps, but
generally these phases are managed with relative ease and have little impact
on requirements, design, and&amp;nbsp;testing.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is not the implementation,  but discovering the requirements, finding a
solid design and defining a test plan are the risky parts of the&amp;nbsp;process.&lt;/p&gt;
&lt;h1&gt;Eliminate development&amp;nbsp;risks&lt;/h1&gt;
&lt;p&gt;In the main part of the paper Royce presents five steps that, in his
experience, increase the likelihood of success.  These&amp;nbsp;are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Program design comes&amp;nbsp;first&lt;/li&gt;
&lt;li&gt;Document the&amp;nbsp;design&lt;/li&gt;
&lt;li&gt;Do it&amp;nbsp;twice&lt;/li&gt;
&lt;li&gt;Plan, control and monitor&amp;nbsp;testing&lt;/li&gt;
&lt;li&gt;Involve the&amp;nbsp;customer&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The process is shown in Figure 4, let&amp;#8217;s see each steps in&amp;nbsp;detail.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure4" src="https://thewagner.net/images/royce1970-figure4c.png" title="Unfortunately, for the process illustrated, the design iterations are never confined to the successive steps"&gt;&lt;/p&gt;
&lt;h2&gt;Program design comes&amp;nbsp;first&lt;/h2&gt;
&lt;p&gt;In center of Figure 4 is &amp;#8220;Program design&amp;#8221;, this is where the process starts.
Program designers lay out the operational design of the program, they &lt;em&gt;design,
define and allocate data processing modes even at the risk of being wrong&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Eventually, all software is about data transformation therefore &lt;a href="https://www.youtube.com/watch?v=rX0ItVEVjHc"&gt;understanding
the data&lt;/a&gt; is key to understanding the problem.  The recommendation
here is detailed and&amp;nbsp;prescriptive:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;Allocate processing, functions, design the database, define database
processing, allocate execution time, define interfaces and processing modes
with the operating system, describe input and output processing, and define
preliminary operating&amp;nbsp;procedures.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The outcome of this phase is an overview document with a goal&amp;nbsp;that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;Each and every worker must have an elemental understanding of the system.
At least one person must have a deep understanding of the system which comes
partially from having had to write an overview&amp;nbsp;document.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Interestingly, in his &lt;a href="https://blog.acolyer.org/2016/09/07/the-emperors-old-clothes/"&gt;1980 Turing-award lecture&lt;/a&gt;, Tony Hoare
recounts a story of a cancelled project from the sixties where he felt
responsible for the failure because he let the programmers do things which
himself didn&amp;#8217;t&amp;nbsp;understand.&lt;/p&gt;
&lt;h2&gt;Document the&amp;nbsp;design&lt;/h2&gt;
&lt;p&gt;Royce starts the longest section of the paper with a categorical&amp;nbsp;statement:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;The first rule of managing software development is ruthless enforcement of
documentation requirements. [&amp;#8230;] Management of software is simply impossible
without a high degree of&amp;nbsp;documentation.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A verbal record is intangible to be a basis for a communication interface or
management decision.  Without a written record one cannot evaluate the
project&amp;#8217;s progress nor its&amp;nbsp;completion.&lt;/p&gt;
&lt;p&gt;Documentation serves as the primary means of communication between people on
different parts of the project: developers, testers, people in operations.
Additionally, good documentation permits effective redesign, updating and
retrofitting without throwing away the entire existing framework of operating&amp;nbsp;software.&lt;/p&gt;
&lt;p&gt;How much documentation is enough?  According to Royce, in 5 million dollar
(approximately 38 million in 2023) software project, an adequate specification
document would be around 1500 pages&amp;nbsp;long.&lt;/p&gt;
&lt;h2&gt;Do it&amp;nbsp;twice&lt;/h2&gt;
&lt;p&gt;If the product is totally original, Royce recommends building a prototype which
he calls an &lt;em&gt;early simulation of the final product&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;If the computer program in question is being developed for the first time,
arrange matters so that the version finally delivered to the customer for
operational deployment is actually the second version insofar as critical
design/operations areas are&amp;nbsp;concerned.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The goal of the prototype is to test which hypotheses hold and identify areas of
the design which are too optimistic.  Royce highlights that the personnel
involved in the pilot must have &lt;em&gt;an intuitive feel for analysis, coding and
program design&lt;/em&gt;.  In other words, the most experienced engineers in the team
should be assigned to this&amp;nbsp;work.&lt;/p&gt;
&lt;h2&gt;Plan, control and monitor&amp;nbsp;testing&lt;/h2&gt;
&lt;p&gt;This part on testing is the second-longest section of the paper, here I
highlight only a few&amp;nbsp;points.&lt;/p&gt;
&lt;p&gt;If the project followed the previous steps, most problems should be already&amp;nbsp;solved:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;The previous three recommendations to design the program before beginning
analysis and coding, to document it completely, and to build a pilot model
are all aimed at uncovering and solving problems before entering the test&amp;nbsp;phase.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this section Royce observes that most errors are obvious, and he argues for
performing code reviews: &lt;em&gt;every bit of code should be subjected to a simple
visual scan by a second party who did not do the original analysis or&amp;nbsp;code.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;He also promotes good test coverage: &lt;em&gt;every logic path in the computer program
at least once with some kind of numerical check&lt;/em&gt;.  He puts the bar high: as a
customer he would insist on nearly 100%&amp;nbsp;coverage.&lt;/p&gt;
&lt;h2&gt;Involve the&amp;nbsp;customer&lt;/h2&gt;
&lt;p&gt;Royce recognizes that even after an agreement, what the desired software is
going to do is a subject of wide interpretation.  He suggests that the customer
is formally involved during design reviews and during the final software
acceptance&amp;nbsp;review.&lt;/p&gt;
&lt;h1&gt;Discussion&lt;/h1&gt;
&lt;p&gt;I am surprised how many ideas, that we consider as &amp;#8220;modern&amp;#8221;, are present in
this paper from 1970.  Designing data flows, pilot projects, code reviews,
customer involvement are all mentioned here by someone who managed projects
during the sixties.  Computing was totally different then, but software
projects suffered the same problem as&amp;nbsp;today.&lt;/p&gt;
&lt;p&gt;More than fifty years later, I feel that the Royce&amp;#8217;s wisdom remains relevant.
Many suggestions in this paper were rediscovered or reformulated later, perhaps
some are still&amp;nbsp;ignored.&lt;/p&gt;
&lt;p&gt;This is a fantastic paper.  The &lt;a href="http://www-scf.usc.edu/~csci201/lectures/Lecture11/royce1970.pdf"&gt;original&lt;/a&gt; is only 11 pages, I highly
recommend reading&amp;nbsp;it.&lt;/p&gt;
&lt;h1&gt;Acknowledgements&lt;/h1&gt;
&lt;p&gt;The figures in this article are from the original&amp;nbsp;paper.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Year 2022 in review</title><link href="https://thewagner.net/blog/2022/12/31/year-2022-in-review/" rel="alternate"/><published>2022-12-31T00:00:00+01:00</published><updated>2022-12-31T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2022-12-31:/blog/2022/12/31/year-2022-in-review/</id><summary type="html">&lt;p&gt;This year I wrote only three articles (including this one), so this will be a
short review of the articles in&amp;nbsp;2022.&lt;/p&gt;
&lt;p&gt;The puzzle of Day 8 in &lt;a href="https://thewagner.net/blog/2021/12/25/advent-of-code-2021/"&gt;2021 Advent of Code&lt;/a&gt; inspired me to &lt;a href="https://thewagner.net/blog/2022/01/23/exploring-logic-programming/"&gt;explore
logic programming&lt;/a&gt;, a lesser known, perhaps forgotten, yet
powerful programming paradigm.  In this article …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This year I wrote only three articles (including this one), so this will be a
short review of the articles in&amp;nbsp;2022.&lt;/p&gt;
&lt;p&gt;The puzzle of Day 8 in &lt;a href="https://thewagner.net/blog/2021/12/25/advent-of-code-2021/"&gt;2021 Advent of Code&lt;/a&gt; inspired me to &lt;a href="https://thewagner.net/blog/2022/01/23/exploring-logic-programming/"&gt;explore
logic programming&lt;/a&gt;, a lesser known, perhaps forgotten, yet
powerful programming paradigm.  In this article I explain my first logic
program and I discuss the advantages and drawbacks I see with the
implementation.  I want to learn more about this paradigm because, as &lt;a href="https://www.youtube.com/watch?v=mRwHZTNGdoY"&gt;Scott
Wlaschin explains in this presentation&lt;/a&gt;, logic programming systems
and libraries may yield elegant declarative solutions to some classes of&amp;nbsp;problems.&lt;/p&gt;
&lt;p&gt;In Summer, I started to volunteer at &lt;a href="https://powerhouse-lausanne.ch"&gt;Powerhouse&lt;/a&gt;, a local
organization helping people to learn programming.  I held only a few coaching
sessions, but the experience rekindled my interest in teaching.  I keep working
with them in next year&amp;nbsp;too.&lt;/p&gt;
&lt;p&gt;Finally, yet again, in December I spent my free time solving the &lt;a href="https://thewagner.net/blog/2022/12/25/advent-of-code-2022/"&gt;Advent of
Code&lt;/a&gt;&amp;nbsp;puzzles.&lt;/p&gt;
&lt;p&gt;Thanks for reading and happy&amp;nbsp;2023!&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Advent of Code 2022</title><link href="https://thewagner.net/blog/2022/12/25/advent-of-code-2022/" rel="alternate"/><published>2022-12-25T00:00:00+01:00</published><updated>2022-12-25T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2022-12-25:/blog/2022/12/25/advent-of-code-2022/</id><summary type="html">&lt;p&gt;Solving the Advent of Code 2022 puzzles in&amp;nbsp;Clojure.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Since 2020, every year I solve the &lt;a href="https://adventofcode.com/"&gt;Advent of Code&lt;/a&gt;
puzzles.  This post, like those of &lt;a href="https://thewagner.net/blog/2020/12/25/advent-of-code-2020/"&gt;previous&lt;/a&gt; &lt;a href="https://thewagner.net/blog/2021/12/25/advent-of-code-2021/"&gt;years&lt;/a&gt;, is an
experience report of my 25+ day journey in&amp;nbsp;December.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: If you&amp;#8217;re still working or planning to work on the puzzles
stop reading&amp;nbsp;now.&lt;/p&gt;
&lt;h1&gt;Puzzles&lt;/h1&gt;
&lt;p&gt;Between December 1 and December 25, a programming puzzle appears every day at
Advent of Code website.  Each problem has two parts, the second part unlocks
after you complete the first.  To understand each day&amp;#8217;s puzzle, go to the
website and read the full description (for example &lt;a href="https://adventofcode.com/2022/day/1"&gt;Day 1: Calorie
Counting&lt;/a&gt;).&lt;/p&gt;
&lt;h1&gt;Setup&lt;/h1&gt;
&lt;p&gt;In  previous years, I used the Advent of Code to learn a new programming
language.  I used Rust in &lt;a href="https://thewagner.net/blog/2020/12/25/advent-of-code-2020/"&gt;2020&lt;/a&gt;, and Clojure in &lt;a href="https://thewagner.net/blog/2021/12/25/advent-of-code-2021/"&gt;2021&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This year I stayed with Clojure.  I feel it&amp;#8217;s a good fit for the Advent of
Code.  Clojure&amp;#8217;s support for interactive development, the built-in data
structures, and the core library functions allowed me to write clear, concise
code that is almost exclusively about the problem at&amp;nbsp;hand.&lt;/p&gt;
&lt;p&gt;I wanted to write idiomatic, readable code.  I don&amp;#8217;t compete on the global
leaderboard, I don&amp;#8217;t care about coding speed, code size and&amp;nbsp;performance.&lt;/p&gt;
&lt;h1&gt;Highlights&lt;/h1&gt;
&lt;p&gt;This year I enjoyed all puzzles, even the hardest ones.  The first two weeks
went well and I followed a regular daily schedule: I solved the day&amp;#8217;s problem
before going to work, sometimes I coded a bit in the evening to polish my&amp;nbsp;solution.&lt;/p&gt;
&lt;p&gt;The difficulties started on &lt;a href="https://github.com/wagdav/advent-of-code-2022/blob/main/src/aoc2022/day15.clj"&gt;Day 15&lt;/a&gt;.  I didn&amp;#8217;t pay attention to the
problem description and I came up with an overly complicated, long, and buggy
solution.  Looking back, I should have stepped away from the problem for a day
or two.  Instead, I kept going and my performance in the next days&amp;nbsp;suffered.&lt;/p&gt;
&lt;p&gt;Exhausted from the previous day, I took another hit on &lt;a href="https://github.com/wagdav/advent-of-code-2022/blob/main/src/aoc2022/day16.clj"&gt;Day 16&lt;/a&gt;  which
was about opening valves to release pressure from a cave.  I tried to formulate
the solution as a shortest-path problem.  My program solved correctly the given
example but it ran out of memory when I gave it the real input.  I also failed
to solve the day as a search problem, as there were too many possibilities to
explore.  Finally, I looked at solutions online and an &lt;a href="https://github.com/wagdav/advent-of-code-2022/blob/main/src/aoc2022/day16.clj"&gt;implementation using
dynamic programming&lt;/a&gt; gave me a good&amp;nbsp;solution.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/wagdav/advent-of-code-2022/blob/main/src/aoc2022/day17.clj"&gt;Day 17&lt;/a&gt; was about playing a variant of Tetris.  The second part asked
how many rows the board has after dropping a &lt;em&gt;trillion&lt;/em&gt; rocks.  Here I also
used some help from others.  The solution runs fast, but the implementation is
clunky: I made it work but I was too tired to clean it&amp;nbsp;up.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/wagdav/advent-of-code-2022/blob/main/src/aoc2022/day19.clj"&gt;Day 19&lt;/a&gt; was about building mining robots that can mine different
resources.  From the description, the problem looked similar to that of &lt;a href="https://github.com/wagdav/advent-of-code-2022/blob/main/src/aoc2022/day16.clj"&gt;Day
16&lt;/a&gt;.  Now I suspect that this similarity was a trap because an efficient
solution ended up looking different.  I borrowed the key idea from &lt;a href="https://github.com/jonathanpaulson/AdventOfCode/blob/master/2022/19.py"&gt;Johnathan
Paulson&lt;/a&gt;: a depth-first search with a limit on the number of mining
robots and the accumulated stock gave a correct and fast&amp;nbsp;solution.&lt;/p&gt;
&lt;p&gt;My favorite day was &lt;a href="https://github.com/wagdav/advent-of-code-2022/blob/main/src/aoc2022/day22.clj"&gt;Day 22&lt;/a&gt; which was about moving around on a map with
&amp;#8220;interesting&amp;#8221; boundary conditions.  I loved the plot twist in the second part
which I don&amp;#8217;t want to spoil.  Many people gave up here, so I&amp;#8217;m proud I made it.
Later I&amp;#8217;d like to generalize my solution because now it only works on the input
generated for my&amp;nbsp;account.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I had a great 2022 Advent of Code, this is my best year so far.  My solutions
are decent and they are my own except parts of &lt;a href="https://github.com/wagdav/advent-of-code-2022/blob/main/src/aoc2022/day16.clj"&gt;Day 16&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code-2022/blob/main/src/aoc2022/day17.clj"&gt;Day 17&lt;/a&gt;
and &lt;a href="https://github.com/wagdav/advent-of-code-2022/blob/main/src/aoc2022/day19.clj"&gt;Day 19&lt;/a&gt; where I used external help.  Maybe next year I&amp;#8217;ll recognize
similar problems to solve all days on my&amp;nbsp;own.&lt;/p&gt;
&lt;p&gt;Solving the puzzles for 25 days next to my full-time job is exhausting.  Perhaps
for a few days, I pushed too hard and I should take more breaks next&amp;nbsp;year.&lt;/p&gt;
&lt;p&gt;As usual, after solving the puzzles I like to see how others approached the
same problem.  Here are some repositories I regularly&amp;nbsp;checked:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/KornelJahn/advent-of-code-2022"&gt;Jahn Kornél&amp;nbsp;(Julia)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jonathanpaulson/AdventOfCode/tree/master/2022"&gt;Jonathan Paulson&amp;nbsp;(Python)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lizthegrey/adventofcode/tree/main/2021"&gt;Liz Fong Jones&amp;nbsp;(Go)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/odormond/adventofcode/tree/master/2021"&gt;Olivier Dormond&amp;nbsp;(Python)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/norvig/pytudes/blob/main/ipynb/Advent-2022.ipynb"&gt;Peter Norvig&amp;nbsp;(Python)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My solutions are available on &lt;a href="https://github.com/wagdav/advent-of-code-2022"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Acknowledgments&lt;/h1&gt;
&lt;p&gt;Thanks &lt;a href="https://twitter.com/ericwastl"&gt;Eric Wastl&lt;/a&gt; for creating and running
&lt;a href="https://adventofcode.com"&gt;Advent of Code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I enjoyed exchanging ideas and analyzing solutions with my friend
&lt;a href="https://github.com/KornelJahn/"&gt;Kornél&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Exploring Logic Programming</title><link href="https://thewagner.net/blog/2022/01/23/exploring-logic-programming/" rel="alternate"/><published>2022-01-23T00:00:00+01:00</published><updated>2022-01-23T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2022-01-23:/blog/2022/01/23/exploring-logic-programming/</id><summary type="html">&lt;p&gt;I revisit the problem &lt;em&gt;Seven Segment Search&lt;/em&gt; of Day 8 in the Advent of Code
2021 puzzle series.  I implement a declarative solution in Clojure using
the logic programming library&amp;nbsp;core.logic.&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this article I revisit the problem &lt;em&gt;Seven Segment Search&lt;/em&gt; of Day 8 in the
&lt;a href="https://thewagner.net/blog/2021/12/25/advent-of-code-2021/"&gt;Advent of Code 2021&lt;/a&gt; puzzle
series.  I implement a declarative solution in Clojure using the logic
programming library &lt;a href="https://github.com/clojure/core.logic/"&gt;core.logic&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Puzzle&lt;/h1&gt;
&lt;p&gt;The &lt;a href="https://adventofcode.com/2021/day/8"&gt;problem of Day 8&lt;/a&gt; was about decoding the digits of a broken
&lt;a href="https://en.wikipedia.org/wiki/Seven-segment_display"&gt;seven-segment&lt;/a&gt; display.  We can measure the signals on the
wires powering the display&amp;#8217;s segments, but we don&amp;#8217;t know which wire is
connected to which segment.  The puzzle input is a sequence of activation
signals of the display as it renders the digits from 0 to 9 in some random&amp;nbsp;order:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;quot;be&amp;quot; &amp;quot;cfbegad&amp;quot; &amp;quot;cbdgef&amp;quot; &amp;quot;fgaecd&amp;quot; &amp;quot;cgeb&amp;quot; &amp;quot;fdcge&amp;quot; &amp;quot;agebfd&amp;quot;
&amp;quot;fecdb&amp;quot; &amp;quot;fabcd&amp;quot; &amp;quot;edb&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The goal of the puzzle is to decode these signal patterns to understand which
digit the display&amp;nbsp;renders.&lt;/p&gt;
&lt;p&gt;For example, the first signal&amp;nbsp;pattern &lt;code&gt;"be"&lt;/code&gt; must be the&amp;nbsp;digit &lt;code&gt;1&lt;/code&gt; because this
is the only digit that is rendered using two segments.  But we don&amp;#8217;t know which
segment the&amp;nbsp;signals &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;e&lt;/code&gt; are connected.  By looking at the&amp;nbsp;digit &lt;code&gt;1&lt;/code&gt;
there are two&amp;nbsp;possibilities:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt; ....       ....
.    b     .    e
.    b     .    e
 ....       ....
.    e     .    b
.    e     .    b
 ....       ....
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In fact, the&amp;nbsp;digits &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;4&lt;/code&gt;, &lt;code&gt;7&lt;/code&gt; and &lt;code&gt;8&lt;/code&gt; each use a unique number of segments:
2, 4, 3 and 7, respectively, so these are easy to identify.  To find the other
digits we need to collect more&amp;nbsp;information.&lt;/p&gt;
&lt;p&gt;For example, the&amp;nbsp;digits &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt; are each contain five active segments.
From this group we can find the&amp;nbsp;digit &lt;code&gt;3&lt;/code&gt; by exploiting that the rendering of
the&amp;nbsp;digit &lt;code&gt;3&lt;/code&gt; doesn&amp;#8217;t change with the&amp;nbsp;digit &lt;code&gt;1&lt;/code&gt; superimposed.  In other words,
the activation signals of the&amp;nbsp;digit &lt;code&gt;3&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; only differ in one&amp;nbsp;segment.&lt;/p&gt;
&lt;h1&gt;Imperative&amp;nbsp;solution&lt;/h1&gt;
&lt;p&gt;Exploiting the similarities between the digit representations you can come up
with your own algorithm to unambiguously identify all digits.  My
implementation in Clojure looks like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;decode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;group-by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="nv"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Unambiguous digits&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get &lt;/span&gt;&lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;four&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get &lt;/span&gt;&lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;seven&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get &lt;/span&gt;&lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;eight&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get &lt;/span&gt;&lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Candiates for 2,3,5 and 0,6,9&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;c235&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get &lt;/span&gt;&lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;c069&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get &lt;/span&gt;&lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; Find the rest using similar digits&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;three&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;find-with-mask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c235&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;find-with-mask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;three&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c069&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;zero&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;find-with-mask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;seven&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;remove &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c069&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;five&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;find-with-mask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;remove &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;three&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c235&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;six&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;remove &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;zero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c069&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;two&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;remove &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;three&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;five&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c235&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;zero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;two&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;three&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;four&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nv"&gt;five&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;six&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;seven&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;eight&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The&amp;nbsp;function &lt;code&gt;decode&lt;/code&gt; takes the signal patterns as input and returns a map from
signal pattern to digit value.  The&amp;nbsp;function &lt;code&gt;find-with-mask&lt;/code&gt; implements the
insight about the similarity of the digits.  You can read the entire code of my
solution &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/92600462261829f4a7069eb43ad6e5930f053e59/src/aoc2021/day08.clj"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Clojure may not be your language of choice, but in any other mainstream
language the solution would be similar in spirit: a few function calls, set and
sequence operations. Each operation is trivial but&amp;nbsp;the &lt;code&gt;decode&lt;/code&gt; function is
hard to understand even for a person familiar with the problem statement.  This
implementation is imperative, each line prescribing what to do and the order of
operations is&amp;nbsp;critical.&lt;/p&gt;
&lt;p&gt;In the next section I show a declarative solution where we only state the
problem and let the computer figure out how to solve&amp;nbsp;it.&lt;/p&gt;
&lt;h1&gt;Declarative&amp;nbsp;solution&lt;/h1&gt;
&lt;p&gt;In this section we reimplement&amp;nbsp;the &lt;code&gt;decode&lt;/code&gt; function using the logic
programming library &lt;a href="https://github.com/clojure/core.logic/"&gt;core.logic&lt;/a&gt;.  A logic program is an expression
of constraints upon a set of logic variables.  We hand this expression to a
solver, in our case core.logic, which returns all the possible values of the
logic variables that satisfy the constraints.  The &lt;a href="https://github.com/clojure/core.logic/wiki/A-Core.logic-Primer"&gt;core.logic
Primer&lt;/a&gt; explains in detail how the solver&amp;nbsp;works.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s see the declarative version of the pattern decoder in Clojure&amp;nbsp;core.logic:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;decode-logic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;group-by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="nv"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;q&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; ❶&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fresh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;zero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;two&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;three&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;four&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;five&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;six&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;seven&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;eight&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; ❷&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;== &lt;/span&gt;&lt;span class="nv"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;zero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;two&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;three&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;four&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="nv"&gt;five&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;six&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;seven&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;eight&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; ❸&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;== &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;== &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;four&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;== &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;seven&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;== &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;eight&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; ❹&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;permuteo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;two&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;three&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;five&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;permuteo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;zero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;six&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; ❺&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;overlay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;three&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;three&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;overlay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;overlay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;zero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;overlay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;five&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; ❻&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;permuteo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;patterns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;zero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;two&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;three&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;four&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="nv"&gt;five&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;six&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;seven&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;eight&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nine&lt;/span&gt;&lt;span class="p"&gt;]))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After a standard function definition and a let-binding the body&amp;nbsp;of
&lt;code&gt;decode-logic&lt;/code&gt; is a set of constraints derived from our original problem&amp;nbsp;statement:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Run the solver and ask for exactly solution.  Our problem has a unique
   solution, but in other applications you may be interested in many solutions
   that satisfy the&amp;nbsp;constraints.  &lt;code&gt;q&lt;/code&gt;, the second argument of
   &lt;a href="https://clojuredocs.org/clojure.core.logic/run"&gt;run&lt;/a&gt;, refers to the final&amp;nbsp;solution.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Search the&amp;nbsp;solution &lt;code&gt;q&lt;/code&gt; in the shape of a map from pattern to digit value.
   This is the same structure we used in the previous&amp;nbsp;section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Identify the &amp;#8220;easy&amp;#8221; digits, those with unambiguous number of active&amp;nbsp;segments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The 5 and 6 character long signal patterns are the permutations of the&amp;nbsp;sequences &lt;code&gt;[2, 3, 5]&lt;/code&gt; and &lt;code&gt;[0, 6, 9]&lt;/code&gt;,&amp;nbsp;respectively.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Overlay rules: for example the digit 1 and 3 yields 3 when on top of each&amp;nbsp;other.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The sequence of activation patterns is a permutation of the&amp;nbsp;digits.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;decode-logic&lt;/code&gt; encodes only the rules of the puzzle without any details of the
program&amp;#8217;s execution.  In fact, you can rearrange the constraints arbitrarily,
the logic expression evaluates to the same&amp;nbsp;result.&lt;/p&gt;
&lt;p&gt;The order of the constraints, however, affects the solver&amp;#8217;s performance: I
found that stating more specific constraints first makes the solver explore the
possible states&amp;nbsp;faster.&lt;/p&gt;
&lt;p&gt;The beauty of the declarative solution comes with a price, at least in my&amp;nbsp;implementation: &lt;code&gt;decode-logic&lt;/code&gt; takes approximately six seconds to run&amp;nbsp;where
&lt;code&gt;decode&lt;/code&gt; completes within a millisecond.  This was my first logic program I&amp;#8217;ve
ever written in Clojure core.logic so I guess this is&amp;nbsp;fine.&lt;/p&gt;
&lt;p&gt;The source code of the implementation is available &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/92600462261829f4a7069eb43ad6e5930f053e59/src/aoc2021/day08b.clj"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I implemented an Advent of Code puzzle as a logic expression in Clojure.  A
logic program is about the &lt;em&gt;what&lt;/em&gt; instead of the &lt;em&gt;how&lt;/em&gt;: stating the problem is
easier, but reasoning about the program&amp;#8217;s performance is harder than compared
to an imperative&amp;nbsp;implementation.&lt;/p&gt;
&lt;p&gt;You can read about my experience of the 2021 Advent of Code
&lt;a href="https://thewagner.net/blog/2021/12/25/advent-of-code-2021/"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code-2021"&gt;this
repository&lt;/a&gt; contains all my&amp;nbsp;solutions.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Year 2021 in review</title><link href="https://thewagner.net/blog/2021/12/31/year-2021-in-review/" rel="alternate"/><published>2021-12-31T00:00:00+01:00</published><updated>2021-12-31T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2021-12-31:/blog/2021/12/31/year-2021-in-review/</id><summary type="html">&lt;p&gt;This year I wrote six posts on this blog (including this one), which is fewer
than the ten written in 2020.  In the first half of the year I was looking for
a new job which sucked up most of my creative energy, but eventually last
Summer I &lt;a href="https://thewagner.net/blog/2021/07/15/leaving-pix4d/"&gt;changed my …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;This year I wrote six posts on this blog (including this one), which is fewer
than the ten written in 2020.  In the first half of the year I was looking for
a new job which sucked up most of my creative energy, but eventually last
Summer I &lt;a href="https://thewagner.net/blog/2021/07/15/leaving-pix4d/"&gt;changed my employer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Back in February I noticed how hard it is to know exactly what software
versions are installed in a container image and I proposed to &lt;a href="https://thewagner.net/blog/2021/02/25/building-container-images-with-nix/"&gt;build container
images using Nix&lt;/a&gt;.  Nix is still the best tool for packaging and
deploying software and I use it everywhere I&amp;nbsp;can.&lt;/p&gt;
&lt;p&gt;On a rainy weekend in March I learned how to &lt;a href="https://thewagner.net/blog/2021/03/07/markov-chain-word-generation/"&gt;generate random blog posts with a
Markov-chain&lt;/a&gt;.  This was great fun and in the future I&amp;#8217;d like to
experiment more with various machine learning&amp;nbsp;algorithms.&lt;/p&gt;
&lt;p&gt;In June my mind was on &lt;a href="https://thewagner.net/blog/2021/06/05/practicing-writing/"&gt;writing&lt;/a&gt;.  I reviewed two books which helped
me to improve my writing and I explained how I practice writing at work and in
my free&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;Finally, in December I spent my free time solving the &lt;a href="https://thewagner.net/blog/2021/12/25/advent-of-code-2021/"&gt;Advent of Code
2021&lt;/a&gt; puzzles to learn the Clojure programming&amp;nbsp;language.&lt;/p&gt;
&lt;p&gt;Thanks for being here, let&amp;#8217;s see what 2022&amp;nbsp;brings!&lt;/p&gt;
&lt;p&gt;Happy New&amp;nbsp;Year!&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Advent of Code 2021</title><link href="https://thewagner.net/blog/2021/12/25/advent-of-code-2021/" rel="alternate"/><published>2021-12-25T00:00:00+01:00</published><updated>2021-12-25T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2021-12-25:/blog/2021/12/25/advent-of-code-2021/</id><summary type="html">&lt;p&gt;Solving the Advent of Code 2021 puzzles in&amp;nbsp;Clojure.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I solved the &lt;a href="https://adventofcode.com/"&gt;Advent of Code&lt;/a&gt;, puzzles.  This post,
&lt;a href="https://thewagner.net/blog/2020/12/25/advent-of-code-2020/"&gt;like the one from last year&lt;/a&gt;,
is an experience report of my 25+ day journey in&amp;nbsp;December.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: If you&amp;#8217;re still working or planning to work on the puzzles
stop reading&amp;nbsp;now.&lt;/p&gt;
&lt;h1&gt;Puzzles&lt;/h1&gt;
&lt;p&gt;Between December 1 and December 25, a programming puzzle appears every day at
Advent of Code website.  Each problem has two parts, the second part unlocks
after you complete the first.  To understand each day&amp;#8217;s puzzle, go to the
website and read the full description (for example &lt;a href="https://adventofcode.com/2021/day/1"&gt;Day 1: Sonar
Sweep&lt;/a&gt;).&lt;/p&gt;
&lt;h1&gt;Setup&lt;/h1&gt;
&lt;p&gt;I decided to learn Clojure and to solve the puzzles in this functional dialect
of the Lisp language.  In the past few years I believe I watched every
available conference talk of Rich Hickey, the creator of Clojure. It was time
for a full-immersion into the language he&amp;nbsp;designed.&lt;/p&gt;
&lt;p&gt;I knew from last year, when I implemented the solutions in Rust, that learning
a new programming language while thinking about challenging puzzles is
frustrating.  So I decided to learn some Clojure before the puzzle series&amp;nbsp;begins.&lt;/p&gt;
&lt;p&gt;In November I read a few chapters of &lt;a href="https://joyofclojure.github.io/"&gt;The Joy of
Clojure&lt;/a&gt; and I &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/warmup.clj"&gt;rewrote&lt;/a&gt; some of my
Advent of Code 2020 solutions in Clojure. With this preparation I could write
decent code from Day 1 but I often restructured my older programs as I learned
more about the&amp;nbsp;language.&lt;/p&gt;
&lt;p&gt;Just like last year, I didn&amp;#8217;t care about code size, performance optimizations
(only when it was the goal of the puzzle) and coding&amp;nbsp;speed.&lt;/p&gt;
&lt;h1&gt;Highlights&lt;/h1&gt;
&lt;p&gt;My favorite puzzles were &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day08.clj"&gt;Day 8&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day13.clj"&gt;Day 13&lt;/a&gt;.  The former was
about decoding the activation signals of a broken seven-segment display and the
latter was about folding a large sheet of transparent paper to reveal a secret
code.  Both problem statements were funny and they fit well into the
Christmas-themed story&amp;nbsp;line.&lt;/p&gt;
&lt;p&gt;The core algorithms of &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day12.clj"&gt;Day 12&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day15.clj"&gt;Day 15&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day23.clj"&gt;Day 23&lt;/a&gt;
were about graph manipulation.  I enjoyed implementing traversals and solutions
to the shortest path&amp;nbsp;problem.&lt;/p&gt;
&lt;p&gt;The puzzles of &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day09.clj"&gt;Day 9&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day11.clj"&gt;Day 11&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day15.clj"&gt;Day 15&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day25.clj"&gt;Day
25&lt;/a&gt; were stated on a two-dimensional grid.  The task of updating the
grid or parts of it appeared in many forms.  In some cases I could write
expressive code using Clojure&amp;#8217;s threading macros and&amp;nbsp;the &lt;code&gt;cond-&amp;gt;&lt;/code&gt; macro, but I
also feel that some of my grid manipulation code is not idiomatic and hard to&amp;nbsp;understand.&lt;/p&gt;
&lt;p&gt;I solved &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day06.clj"&gt;Day 6&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day14.clj"&gt;Day 14&lt;/a&gt; using infinite sequences.  Here
Clojure really shines: the core sequence manipulation algorithms work well
together resulting in short and expressive&amp;nbsp;code.&lt;/p&gt;
&lt;p&gt;On &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day16.clj"&gt;Day 16&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day18.clj"&gt;Day 18&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day21.clj"&gt;Day 21&lt;/a&gt; recognizing trees,
recursion and the need for memoization were the key elements to write a clean&amp;nbsp;solution.&lt;/p&gt;
&lt;p&gt;I spent the most hours on &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day17.clj"&gt;Day 17&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day19.clj"&gt;Day 19&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day22.clj"&gt;Day 22&lt;/a&gt;.
After multiple failed attempts to solve these days I looked for hints on
&lt;a href="https://www.reddit.com/r/adventofcode/"&gt;Reddit&lt;/a&gt;.  Many smart people hang out
in that forum and there&amp;#8217;s a lot to learn from the conversations&amp;nbsp;there.&lt;/p&gt;
&lt;p&gt;My least favorite day was &lt;a href="https://github.com/wagdav/advent-of-code-2021/blob/main/src/aoc2021/day24.clj"&gt;Day 24&lt;/a&gt;. I didn&amp;#8217;t see the point in
deciphering someone else&amp;#8217;s obfuscated code.  I do this enough at work&amp;nbsp;already.&lt;/p&gt;
&lt;h1&gt;Learning&amp;nbsp;Clojure&lt;/h1&gt;
&lt;p&gt;Using this puzzle series to learn a new programming language is stressful, but
effective.  Just like last year, solving these puzzles left me with some
thoughts about&amp;nbsp;Clojure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="caps"&gt;REPL&lt;/span&gt;&lt;/em&gt;: One big selling point of Clojure is its support for interactive
  development.  I set up my editor with
  &lt;a href="https://github.com/Olical/conjure"&gt;Conjure&lt;/a&gt; and in a few hours I got used to
  evaluating pieces of code directly from the&amp;nbsp;editor.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Testing&lt;/em&gt;: I struggled to set up Cognitect test runner, but once I learned
  the proper way to structure my project things just worked all right.   When
  I&amp;#8217;m using other languages I run the tests from a separate command terminal.
  With Clojure it&amp;#8217;s easy to run the tests without leaving my&amp;nbsp;editor.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Core functions&lt;/em&gt;: Clojure core contains a ton of useful functions which are
  easy to use.  I used only one external library:
  &lt;a href="https://github.com/clojure/data.priority-map/"&gt;data.priority-map&lt;/a&gt;. The
  built-in documentation is terse and short on examples but
  &lt;a href="https://clojuredocs.org"&gt;ClojueDocs&lt;/a&gt; improves this and I used it all the&amp;nbsp;time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Regular expressions&lt;/em&gt;: Last year I spent a lot of time of writing parsers for
  the input files.  This year I used regular expressions almost exclusively
  and the parsing code is rarely longer than a few lines.  Clojure&amp;#8217;s literal
  regular expressions syntax and the&amp;nbsp;function &lt;code&gt;re-seq&lt;/code&gt;, which returns a
  sequence of successive matches, are&amp;nbsp;great.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Proponents of Clojure claim that programs written in this language are short
and expressive because they are mainly about the problem at hand and not about
classes, accessors, lifetimes and other incidental programming language&amp;nbsp;constructs.&lt;/p&gt;
&lt;p&gt;In the past few weeks coding in Clojure I find this claim justified.  In the
future I&amp;#8217;d love to explore how is it to build a large system in the style of
programming Clojure encourages, that is using functions and generic data&amp;nbsp;transformations.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Completing the Advent of Code and learning a new programming language was
challenging, but a rewarding experience.  After solving the puzzles I like to
see how others approached the same problem.  Here are some repositories I
regularly&amp;nbsp;checked:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/lizthegrey/adventofcode/tree/main/2021"&gt;Liz Fong Jones&amp;nbsp;(Go)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/odormond/adventofcode/tree/master/2021"&gt;Olivier Dormond&amp;nbsp;(Python)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/norvig/pytudes/blob/main/ipynb/Advent-2021.ipynb"&gt;Peter Norvig&amp;nbsp;(Python)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The source code of my solutions are also available on &lt;a href="https://github.com/wagdav/advent-of-code-2021"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Acknowledgment&lt;/h1&gt;
&lt;p&gt;Thanks &lt;a href="https://twitter.com/ericwastl"&gt;Eric Wastl&lt;/a&gt; for creating and running
&lt;a href="https://adventofcode.com"&gt;Advent of Code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks Olivier Dormond for exchanging ideas and congratulations for winning our
private&amp;nbsp;leaderboard!&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Leaving Pix4D</title><link href="https://thewagner.net/blog/2021/07/15/leaving-pix4d/" rel="alternate"/><published>2021-07-15T00:00:00+02:00</published><updated>2021-07-15T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2021-07-15:/blog/2021/07/15/leaving-pix4d/</id><summary type="html">&lt;p&gt;After four years at Pix4D it&amp;#8217;s time to move&amp;nbsp;on.&lt;/p&gt;</summary><content type="html">&lt;p&gt;After four years at &lt;a href="https://www.pix4d.com"&gt;Pix4D&lt;/a&gt;, today is my last working day.  This article
presents my main projects and some lessons learned at this&amp;nbsp;company.&lt;/p&gt;
&lt;h1&gt;Calibration&amp;nbsp;Team&lt;/h1&gt;
&lt;p&gt;I joined Pix4D&amp;#8217;s Calibration Team in August 2017 as a C++ developer.  My first
task was to improve the quality report generated by the first stage of
&lt;a href="https://www.pix4d.com/product/pix4dmapper-photogrammetry-software"&gt;PIX4Dmapper&lt;/a&gt;&amp;#8216;s image processing&amp;nbsp;pipeline.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Best times:&lt;/em&gt; I learned a about &lt;a href="https://en.wikipedia.org/wiki/Photogrammetry"&gt;photogrammetry&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Worst times:&lt;/em&gt; I rearranged a data structure in some reporting code and the
  performance of a seemingly unrelated module dropped 10%.  The team spent
  weeks tracking down why this&amp;nbsp;happened.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lesson learned:&lt;/em&gt; Fighting code complexity is the hardest problem in
  maintaining a successful software&amp;nbsp;product.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Integration&amp;nbsp;Team&lt;/h1&gt;
&lt;p&gt;In 2018 I joined the Integration Team to work on a new build automation system
for the company.  Developers needed a tool to build and test their applications
and libraries on various platforms.  I developed an interest in building cloud
infrastructure and deployment&amp;nbsp;pipelines.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Best times:&lt;/em&gt; I learned about Amazon Web Services and about modern tools for
  deploying distributed&amp;nbsp;systems.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Worst times:&lt;/em&gt; Because of an unpinned dependency we picked up a kernel update
  with a bug that crippled our entire fleet of build&amp;nbsp;machines.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lesson learned:&lt;/em&gt; When working on a green-field project our head is full of
  creative ideas and it&amp;#8217;s easy to &lt;a href="https://en.wikipedia.org/wiki/Reinventing_the_wheel"&gt;miss prior work&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The experience in this team inspired me to experiment with &lt;a href="https://thewagner.net/blog/2020/10/18/kevlar/"&gt;my own build
automation system&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Cloud Services&amp;nbsp;Team&lt;/h1&gt;
&lt;p&gt;At the end of 2019 I was invited to join Cloud Services, the team responsible
for Pix4D&amp;#8217;s photogrammetry processing service.  I was excited to work on a live
system serving paying customers.  I also had a chance to lead the technical
work of a small&amp;nbsp;team.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Best times:&lt;/em&gt; I learned about the operation and maintenance of a production
  cloud&amp;nbsp;system.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Worst times:&lt;/em&gt; Browsing through a hundred &lt;span class="caps"&gt;SQS&lt;/span&gt; queues trying to
  reverse-engineer what they&amp;#8217;re&amp;nbsp;for.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lesson learned:&lt;/em&gt; Building things incrementally is a good idea.  Figuring out
  what &lt;em&gt;not&lt;/em&gt; to build is a better&amp;nbsp;idea.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The work in this team &lt;a href="https://thewagner.net/blog/2020/04/30/exploring-nix/"&gt;rekindled my interest in Nix&lt;/a&gt; and led me to
&lt;a href="https://thewagner.net/blog/2020/05/31/homelab/"&gt;build a decent Homelab&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;After four great years at Pix4D I&amp;#8217;m moving on.  I accepted a job at
&lt;a href="https://www.nexthink.com/"&gt;Nexthink&lt;/a&gt; where I keep learning about the
intricacies of cloud&amp;nbsp;systems.&lt;/p&gt;
&lt;p&gt;I wish everybody at Pix4D a lot of&amp;nbsp;success!&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Practicing writing</title><link href="https://thewagner.net/blog/2021/06/05/practicing-writing/" rel="alternate"/><published>2021-06-05T00:00:00+02:00</published><updated>2021-06-05T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2021-06-05:/blog/2021/06/05/practicing-writing/</id><summary type="html">&lt;p&gt;In the past years I have been learning about technical writing.  In this
article I review two books that helped me to improve my writing skills.
Then, I present how I practice writing at home and at&amp;nbsp;work.&lt;/p&gt;</summary><content type="html">&lt;p&gt;In the past years I have been learning about technical writing.  In this article
I review two books that helped me to improve my writing skills. Then, I present
how I practice writing at home and at&amp;nbsp;work.&lt;/p&gt;
&lt;h1&gt;Discovering&amp;nbsp;writing&lt;/h1&gt;
&lt;p&gt;As a scientist I published technical reports, journal papers and even a 200
pages long &lt;a href="https://infoscience.epfl.ch/record/186309"&gt;doctoral thesis&lt;/a&gt;, but I knew little about &lt;em&gt;writing&lt;/em&gt;, a
communication skill that can be learned and improved.  I left academia and I
got a job as a software engineer.  I stopped following science and started
learning programming languages and study industry best&amp;nbsp;practices.&lt;/p&gt;
&lt;p&gt;One summer I read &lt;a href="https://basecamp.com/books/rework"&gt;&lt;span class="caps"&gt;REWORK&lt;/span&gt;&lt;/a&gt;, a book written by Basecamp&amp;#8217;s founders.  The
chapter &lt;em&gt;Hire great writers&lt;/em&gt; explains the authors&amp;#8217; preference in hiring
candidates who can demonstrate great writing skills because clear and efficient
written communication is essential in their distributed and asynchronous
working style.  I was an employee and I didn&amp;#8217;t plan to hire anybody, but the
emphasis on high-quality writing inspired me to become a better&amp;nbsp;writer.&lt;/p&gt;
&lt;p&gt;I looked at my own &lt;a href="https://thewagner.net/blog/2016/07/20/working-habits/"&gt;working habits&lt;/a&gt;
and, somewhat naively, realized the obvious: &lt;em&gt;I write all the time&lt;/em&gt;.  Instant
messaging, code commits, pull-requests, code reviews, project proposals,
incident reports are all a form of writing.  I wanted to learn what good
writing is and how to write&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;I searched for resources targeted at  practitioners who write technical text.
In the next sections I present two books from which I learned the&amp;nbsp;most.&lt;/p&gt;
&lt;h1&gt;Book: &lt;span class="caps"&gt;BUGS&lt;/span&gt; In&amp;nbsp;Writing&lt;/h1&gt;
&lt;p&gt;The book &lt;a href="https://www.amazon.com/BUGS-Writing-Revised-Guide-Debugging/dp/020137921X"&gt;&lt;span class="caps"&gt;BUGS&lt;/span&gt; In Writing by Lyn Dupré&lt;/a&gt; is a catalog of common
mistakes.  It comprises short, easily digestible segments.  Each segment
presents a principle to make your technical writing clear and lucid.  The
principles are illustrated by witty example phrases and numerous cat&amp;nbsp;photos.&lt;/p&gt;
&lt;p&gt;I encountered this book through a reference in Chris Okasaki&amp;#8217;s thesis &lt;a href="https://www.cs.cmu.edu/~rwh/theses/okasaki.pdf"&gt;Purely
Functional Data Structures&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I was extremely fortunate to have had excellent English teachers in high
school. Lori Huenink deserves special recognition; her writing and public
speaking classes are undoubtedly the most valuable classes I have ever taken,
in any subject. In the same vein, I was lucky enough to read my wife&amp;#8217;s copy
of Lyn Dupré&amp;#8217;s &lt;span class="caps"&gt;BUGS&lt;/span&gt; in Writing just as I was starting my thesis. If your
career involves writing in any form, you owe it to yourself to buy a copy of
this&amp;nbsp;book.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I read this recommendation I immediately ordered a copy.  &lt;em&gt;&lt;span class="caps"&gt;BUGS&lt;/span&gt; in
Writing&lt;/em&gt; is a fantastic handbook.  When I have doubts about a specific word or
expression I search for advise in the&amp;nbsp;book.&lt;/p&gt;
&lt;p&gt;To give a taste of Dupré&amp;#8217;s style, here&amp;#8217;s an example from the segment &lt;em&gt;Impact&lt;/em&gt;,
where you learn about the one of the most overused, ugly words in the English&amp;nbsp;language:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are only two pleasing uses of &lt;em&gt;impact&lt;/em&gt;: to denote a forceful collision,
and to mean packed or wedged&amp;nbsp;in.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here the principle is&amp;nbsp;that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[&amp;#8230;] you should not use &lt;em&gt;impact&lt;/em&gt; when you mean &lt;em&gt;influence&lt;/em&gt; or &lt;em&gt;effect&lt;/em&gt;, and
you certainly should not use &lt;em&gt;impact&lt;/em&gt; when you mean &lt;em&gt;affect&lt;/em&gt;, because
impacting people is incredibly&amp;nbsp;impolite.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When you learn about such principles you develop ear for detecting bugs in
texts and your tolerance for buzzwords and corporate jargon&amp;nbsp;decreases.&lt;/p&gt;
&lt;h1&gt;Book: On Writing&amp;nbsp;Well&lt;/h1&gt;
&lt;p&gt;William Zinsser &lt;a href="https://www.amazon.com/Writing-Well-Classic-Guide-Nonfiction/dp/0060891548"&gt;On Writing Well&lt;/a&gt; is really what its subtitle
claims: the classic guide to writing nonfiction.  This book showed me how a
professional writer thinks about writing methods, style, structure and genres.
The book has a chapter on writing about science and technology, but it also
treats business writing, writing about arts, sports and even&amp;nbsp;memoirs.&lt;/p&gt;
&lt;p&gt;Zinsser warns about clutter, every piece of text that doesn&amp;#8217;t do useful work.
He suggests stripping every sentence to its barest bones: delete pompous words,
redundant adjectives, jargon and replace laborious phrases with short words
that mean the same&amp;nbsp;thing.&lt;/p&gt;
&lt;p&gt;Writing a clean sentence is hard work.  And the work is non-linear and
iterative: &lt;em&gt;rewriting is the essence of writing&lt;/em&gt; as Zinsser puts&amp;nbsp;it.&lt;/p&gt;
&lt;h1&gt;Writing a&amp;nbsp;blog&lt;/h1&gt;
&lt;p&gt;In 2013 I published the &lt;a href="https://thewagner.net/blog/2013/03/06/hello-world/"&gt;first article&lt;/a&gt; on this blog. I wanted to
write, but I didn&amp;#8217;t know what to write about.  A common dilemma of the aspiring
writer.  In a few years I published a handful of short articles on random
topics.  Some of them were meta-articles on &lt;a href="https://thewagner.net/blog/2013/03/08/pelican-up-and-running/"&gt;setting up this
blog&lt;/a&gt;.  Some were as simple as connecting a &lt;a href="https://thewagner.net/blog/2013/06/26/led-and-button/"&gt;&lt;span class="caps"&gt;LED&lt;/span&gt; and a
button&lt;/a&gt; to a Raspberry Pi.  Unexpectedly, I had a few &amp;#8220;hits&amp;#8221; too: many
friends liked the article on &lt;a href="https://thewagner.net/blog/2016/07/20/working-habits/"&gt;my working habits&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Around 2017 I changed my writing strategy.  Instead of overthinking the subject
of my next article, I decided that my hobby projects should end with an entry
on my blog.  While working on a project I take notes and write outlines.  When
I&amp;#8217;m finished (or bored) I have a seed of a new article.  I still have to work
hard to make my notes into a coherent story, but I feel that the goal, the
published article, is&amp;nbsp;reachable.&lt;/p&gt;
&lt;h1&gt;Writing at&amp;nbsp;work&lt;/h1&gt;
&lt;p&gt;In my team we improve code using pull-requests, changes that typically comprise
few dozen to few hundred lines of code.  We prefer small batches of code
changes that are easy to review.  The risk of breaking existing systems is
lower than if we changed everything at once.  But through these incremental
changes it&amp;#8217;s hard to see the context in which a given pull-request makes&amp;nbsp;sense.&lt;/p&gt;
&lt;p&gt;I felt the team needed a document that shows how each code change fits into the
story of the project.  Earlier, my team had considered writing &lt;a href="https://en.wikipedia.org/wiki/Change_request"&gt;change request
documents&lt;/a&gt; but some felt it bureaucratic and, frankly, we didn&amp;#8217;t know how to
write them&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;Last December at work I started a new project that required changes in many
subsystems.  I described my implementation plan on the company wiki.  In few
sentences I created a &lt;em&gt;design document&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I started the implementation and as I learned more about the problem domain I
refined the design and I updated the document with my progress.  If you&amp;#8217;d read
the document you would have known what&amp;#8217;s been done and what&amp;#8217;s left to do. The
wiki page became a &lt;em&gt;project page&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Of course my initial design had holes and I discovered traps and dead ends.  I
recorded my failings on the same wiki page which evolved into an &lt;em&gt;experience
report&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When I finished the implementation I collected instructions for operators, the
support team and for other developers, transforming the page into &lt;em&gt;project
documentation&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A few months later when I reread this page I found a &lt;em&gt;historical record&lt;/em&gt; that
explains why and how we arrived to state we have&amp;nbsp;today.&lt;/p&gt;
&lt;p&gt;During this process I found a few practices&amp;nbsp;useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I rewrite the same document as we work on the project.  The document is
  always the entry point for all project-relevant&amp;nbsp;information.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I write prose with complete sentences to build context.  A few words with
  bullet points, list of ticket IDs are&amp;nbsp;insufficient.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I often reference related content.  There&amp;#8217;s no need to repeat what&amp;#8217;s
  explained&amp;nbsp;elsewhere.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I share every major revision with my colleagues asking for reviews and&amp;nbsp;suggestions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The time spent evolving this page was worth it.  I felt that the state of the
page reflected the stage of the project.  If a project needs long pages to
explain, it&amp;#8217;s too big.  If a few words can&amp;#8217;t express what I&amp;#8217;m doing, the
project is ill-defined, or I lack some knowledge to execute&amp;nbsp;it.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I wrote during my whole career, but only lately I have been cultivating my
writing skills.  I practice writing in my free time and professionally.  I
document my hobby projects and software experiments on my blog and I write
&amp;#8220;evolving&amp;#8221; documents on the company&amp;#8217;s internal&amp;nbsp;wiki.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Markov-chain word generation</title><link href="https://thewagner.net/blog/2021/03/07/markov-chain-word-generation/" rel="alternate"/><published>2021-03-07T00:00:00+01:00</published><updated>2021-03-07T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2021-03-07:/blog/2021/03/07/markov-chain-word-generation/</id><summary type="html">&lt;p&gt;Recently I reread some chapters of the book &lt;a href="https://www.cs.princeton.edu/~bwk/tpop.webpage/"&gt;The Practice of Programming by
Brian Kernighan and Rob Pike&lt;/a&gt;.  In Chapter 3 on &lt;em&gt;Design and
Implementation&lt;/em&gt; the authors present several implementations of a random text
generator to compare how various languages&amp;#8217; idioms express the same&amp;nbsp;idea.&lt;/p&gt;
&lt;p&gt;I wrote my version in …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Recently I reread some chapters of the book &lt;a href="https://www.cs.princeton.edu/~bwk/tpop.webpage/"&gt;The Practice of Programming by
Brian Kernighan and Rob Pike&lt;/a&gt;.  In Chapter 3 on &lt;em&gt;Design and
Implementation&lt;/em&gt; the authors present several implementations of a random text
generator to compare how various languages&amp;#8217; idioms express the same&amp;nbsp;idea.&lt;/p&gt;
&lt;p&gt;I wrote my version in Rust which I present in this article with some example
text I generated using various&amp;nbsp;sources.&lt;/p&gt;
&lt;h1&gt;Random&amp;nbsp;text&lt;/h1&gt;
&lt;p&gt;The goal is to write a program that generates random English text that reads
well.  The program takes a large body of text as input to construct a
statistical model of the language as used in that text.  Then the program
generates random text that has similar statistics to the&amp;nbsp;original.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s an example generated sentence, given the words of all articles of this&amp;nbsp;blog:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In this article resonate with you I recommend to watch the original talk on
YouTube with meticulously prepared slides, what we see similar configuration
blocks&amp;nbsp;everywhere.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is obviously nonsense, but the program may generate some funny phrases,
especially if the input is long and&amp;nbsp;varied.&lt;/p&gt;
&lt;p&gt;The program uses a &lt;a href="https://en.wikipedia.org/wiki/Markov_chain"&gt;Markov-chain&lt;/a&gt; algorithm to generate text.  The
words of the input text are arranged in a data structure that records which
two-word combinations are followed by which&amp;nbsp;words.&lt;/p&gt;
&lt;p&gt;For example, let&amp;#8217;s assume that in the input text the words &lt;em&gt;In this&lt;/em&gt; are
followed by one of the following words: &lt;em&gt;example, post, workshop, specific,
representation&lt;/em&gt;.  Starting from &lt;em&gt;In this&lt;/em&gt;, we generate the next word by
choosing randomly from these candidates.  Let&amp;#8217;s say we pick &lt;em&gt;specific&lt;/em&gt;.  Then,
in the next iteration we repeat the same procedure for the words &lt;em&gt;this
specific&lt;/em&gt;.  We can continue generating new words until we have candidate words
to pick&amp;nbsp;from.&lt;/p&gt;
&lt;h1&gt;Rust&amp;nbsp;implementation&lt;/h1&gt;
&lt;p&gt;I wrote my version of the word generator program in Rust.  This code snippet
shows its basic&amp;nbsp;usage:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ChainBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;// ①&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="c1"&gt;// ②&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// ③&lt;/span&gt;
&lt;span class="fm"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ④&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;a href="https://rust-unofficial.github.io/patterns/patterns/creational/builder.html"&gt;ChainBuilder&lt;/a&gt;.  The chain will use two-word prefixes
   to detemine the next&amp;nbsp;word.&lt;/li&gt;
&lt;li&gt;Add words from the input text and store them in a hash-map&amp;nbsp;internally.&lt;/li&gt;
&lt;li&gt;Finish building and create the&amp;nbsp;actual &lt;code&gt;Chain&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use&amp;nbsp;the &lt;code&gt;Chain&lt;/code&gt; to generate 100 words and print them as a&amp;nbsp;sentence.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The whole implementation is 129 lines long and it&amp;#8217;s available on
&lt;a href="https://github.com/wagdav/markov"&gt;GitHub&lt;/a&gt;.  It&amp;#8217;s a complete command-line application with help texts
and proper argument parsing.  The used algorithm and data structures are
identical to those described in &lt;a href="https://www.cs.princeton.edu/~bwk/tpop.webpage/"&gt;the book&lt;/a&gt;.  You can also find the C,
C++, Java, Perl and &lt;span class="caps"&gt;AWK&lt;/span&gt; versions written by Kernighan and Pike
&lt;a href="https://www.cs.princeton.edu/~bwk/tpop.webpage/code.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Examples&lt;/h1&gt;
&lt;p&gt;Let&amp;#8217;s see some generated texts based on different data sets.  The prefix length
is always two.  The code gives a random text at each execution and I ran the
program a few times until I obtained a variant which I found funny or
interesting.  Often I stripped the unfinished, partial sentences from the end
of the&amp;nbsp;text.&lt;/p&gt;
&lt;h2&gt;Book of&amp;nbsp;Psalms&lt;/h2&gt;
&lt;p&gt;Kernighan and Pike use the &lt;a href="https://www.gutenberg.org/ebooks/8019"&gt;Book of Psalms from the King James Bible&lt;/a&gt;
as a test dataset because it  has many repeated phrases (&lt;em&gt;Blessed is the&amp;#8230;&lt;/em&gt;)
which provides chains with large suffix sets.  I started to test my program
with this data set.  Here&amp;#8217;s one&amp;nbsp;example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Blessed is the lord. Praise the lord, at the blast of the enemy: thou hast
maintained my right hand is full of water: thou preparest them corn, when
thou hast known my soul had almost dwelt in&amp;nbsp;silence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Indeed, the characteristics of the input dataset are recognizable in each
random output,  the text reads like prayer using archaic English&amp;nbsp;words.&lt;/p&gt;
&lt;h2&gt;Technobabble&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://science.ksc.nasa.gov/shuttle/missions/51-l/docs/rogers-commission/Appendix-F.txt"&gt;Richard Feynman&amp;#8217;s observations on the reliability of the Shuttle&lt;/a&gt; is
a fantastic read on it own.  The 5000 word long eloquent, technical text is an
excellent source for technobabble&amp;nbsp;generation.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It appears that there are three engines, but some accidents would possibly be
contained, and only three in the second 125,000 seconds. Naturally, one can
never be sure that all is safe by inspecting all blades for cracks. If they
are found, replace them, and if none are found in the list above). These we
discuss below. (Engineers at Rocketdyne, were&amp;nbsp;made.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this example we can see that the implementation has no notion of
punctuation: unmatched parentheses appear at random places because they are
considered to be part of the&amp;nbsp;word.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s another&amp;nbsp;one:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It appears that there are enormous differences of opinion as to the Space
Shuttle Main Engine. Cracks were found after 4,200 seconds, although usually
these longer runs showed cracks. To follow this story further we shall have to
realize that the rule seems to have been&amp;nbsp;solved.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Blog&amp;nbsp;corpus&lt;/h2&gt;
&lt;p&gt;Finally I tried to generate a random blog post using the articles I&amp;#8217;ve written&amp;nbsp;here.&lt;/p&gt;
&lt;p&gt;I used &lt;a href="https://pandoc.org"&gt;Pandoc&lt;/a&gt; to convert the markdown files I&amp;#8217;ve written
to plain&amp;nbsp;text:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pandoc&lt;span class="w"&gt;  &lt;/span&gt;*.markdown&lt;span class="w"&gt; &lt;/span&gt;--from&lt;span class="w"&gt; &lt;/span&gt;markdown&lt;span class="w"&gt; &lt;/span&gt;--to&lt;span class="w"&gt; &lt;/span&gt;plain
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This yields about 20 thousand words of text, some of which appear in equations,
enumerations and code blocks.  I wrote a function to ignore almost everything
but the actual text.   Here are two examples which show that the program is not
quite ready to replace me in writing new&amp;nbsp;articles:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In this representation we can assume that we exploit that &lt;span class="caps"&gt;IO&lt;/span&gt; is a simple
function. Its imaginary type signature is: This reads: the configuration blocks
we implicitly created a simple function. Its imaginary type signature is: This
reads: the configuration code on&amp;nbsp;GitHub.&lt;/p&gt;
&lt;p&gt;In this niche domain the utility of functions is well studied and understood.
Ideas from purely functional programming language using &lt;span class="caps"&gt;YAML&lt;/span&gt;’s syntax. In
programming we use fmap to lift our pure project function to be Python, but it
was served from. We now are ready to define components, component configuration
and component&amp;nbsp;relationships.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In these outputs I can recognize full sentences of my previous articles which
shows that the blog corpus is not large enough for automatic&amp;nbsp;blogging.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Using a Markov-chain to generate random text in a given &amp;#8220;style&amp;#8221; is a fun
programming exercise.  The problem can be solved in a few dozen lines of code,
but it teaches a lot about algorithms and design in&amp;nbsp;general.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Building container images with Nix</title><link href="https://thewagner.net/blog/2021/02/25/building-container-images-with-nix/" rel="alternate"/><published>2021-02-25T00:00:00+01:00</published><updated>2021-02-25T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2021-02-25:/blog/2021/02/25/building-container-images-with-nix/</id><summary type="html">&lt;p&gt;Dockerfiles are de facto standard for creating container images.  In this
article I highlight some issues with this approach and I propose building
container images with&amp;nbsp;Nix.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;code&gt;Dockerfiles&lt;/code&gt; are de facto standard for creating container images.  In this
article I highlight some issues with this approach and I propose building
container images with&amp;nbsp;Nix.&lt;/p&gt;
&lt;h1&gt;Container&amp;nbsp;images&lt;/h1&gt;
&lt;p&gt;Many compute engines adopted &lt;a href="https://opencontainers.org"&gt;container images&lt;/a&gt; as an interface between
your code and their runtime platform.  You package your application in a
self-contained bundle and hand it over to your compute engine of choice for
execution.  The compute engine&amp;#8217;s runtime system creates one or many container
instances based on the provided image and runs your application using some form
of&amp;nbsp;isolation.&lt;/p&gt;
&lt;p&gt;Typically the application doesn&amp;#8217;t have access to any software packages
installed on the physical computer where it runs.  Therefore, the application
can only run correctly in a container if all of its software dependencies are
also packaged in the same&amp;nbsp;image.&lt;/p&gt;
&lt;h1&gt;Dockerfile&lt;/h1&gt;
&lt;p&gt;The canonical way of creating container images is via&amp;nbsp;a &lt;code&gt;Dockerfile&lt;/code&gt;.  For
example, let&amp;#8217;s create an image for a &lt;a href="https://github.com/docker/labs/blob/master/beginner/flask-app/Dockerfile"&gt;web application written in
Python&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:3.5&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c"&gt;# ①&lt;/span&gt;

&lt;span class="k"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;apk&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;--update&lt;span class="w"&gt; &lt;/span&gt;py2-pip&lt;span class="w"&gt;  &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;②

&lt;span class="k"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;--upgrade&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt;  &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;③

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;requirements.txt&lt;span class="w"&gt; &lt;/span&gt;/usr/src/app/&lt;span class="w"&gt;  &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;④
&lt;span class="k"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;--no-cache-dir&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;/usr/src/app/requirements.txt&lt;span class="w"&gt;  &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;⑤
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;app.py&lt;span class="w"&gt; &lt;/span&gt;/usr/src/app/&lt;span class="w"&gt;  &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;⑥
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;templates/index.html&lt;span class="w"&gt; &lt;/span&gt;/usr/src/app/templates/&lt;span class="w"&gt;  &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;⑦

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;5000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/src/app/app.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a short, working example which you can use to deploy a non-trivial web
application.  But if you look closely, there are some issues with&amp;nbsp;this
&lt;code&gt;Dockerfile&lt;/code&gt;.  Let&amp;#8217;s see them, line by&amp;nbsp;line:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;FROM&lt;/code&gt; keyword indicates that we&amp;#8217;re starting from a base image.  In other
   words, we define a dependency on a binary blob.  You may not know what
   programs and libraries the selected base image contains.  In this specific
   case, the Alpine Linux Docker images are described in &lt;a href="https://github.com/alpinelinux/docker-alpine"&gt;this
   repository&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;apk&lt;/code&gt; package manager, part of the base image, installs &lt;em&gt;some&lt;/em&gt; version
   of the Python interpreter which is required to run our application.
   Because we don&amp;#8217;t specify the exact version, every time you build this image
   you may install different&amp;nbsp;versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We&amp;nbsp;install &lt;code&gt;pip&lt;/code&gt; which we&amp;#8217;ll need at subsequent build steps, but not when
   the application is running.  The problem of the unpredictable versions,
   mentioned in the previous item, applies here as&amp;nbsp;well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We copy&amp;nbsp;the &lt;code&gt;requirements.txt&lt;/code&gt; to the image.  This also only required for
   building the&amp;nbsp;image.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;pip&lt;/code&gt; package manager installs the run-time dependencies of our
   application.&amp;nbsp;If &lt;code&gt;requirements.txt&lt;/code&gt; specifies exact version numbers we know
   exactly which packages will be in the final&amp;nbsp;image.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We copy the application, which is only a single file in this&amp;nbsp;case.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We copy an &lt;span class="caps"&gt;HTML&lt;/span&gt; template, also required during&amp;nbsp;run-time.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each line transfers some component into the final container image.  However,&amp;nbsp;the &lt;code&gt;Dockerfile&lt;/code&gt;&lt;span class="quo"&gt;&amp;#8216;&lt;/span&gt;s imperative language fails to capture precisely our
application&amp;#8217;s&amp;nbsp;dependencies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Extra components&lt;/em&gt;: some dependencies are only needed to build the image,
  some are essential for the application to execute correctly.  Yet, both
  kinds end up in the final image.  For&amp;nbsp;example: &lt;code&gt;pip&lt;/code&gt;, &lt;code&gt;apk&lt;/code&gt;,&amp;nbsp;and
  &lt;code&gt;requirements.txt&lt;/code&gt; are not needed in the final&amp;nbsp;image.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Implicit dependencies&lt;/em&gt;: The image contains all packages from the base image
  but it&amp;#8217;s not clear which ones are actual&amp;nbsp;dependencies.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Non-determinism&lt;/em&gt;: The version of most of the dependencies are not pinned.  At
  each build different versions may be&amp;nbsp;installed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Package managers&lt;/em&gt;: we use four different ways to manage dependencies: base
  image with&amp;nbsp;the &lt;code&gt;FROM&lt;/code&gt; keyword, &lt;code&gt;pip&lt;/code&gt;, &lt;code&gt;apk&lt;/code&gt; and copying&amp;nbsp;files.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;nbsp;find &lt;code&gt;Dockerfiles&lt;/code&gt; with such structure used by many software projects.  I
took this section&amp;#8217;s example from a &lt;em&gt;Docker for Beginners&lt;/em&gt;
&lt;a href="https://github.com/docker/labs/tree/master/beginner"&gt;repository&lt;/a&gt;.  In the next
section we&amp;#8217;ll see how novice users  write&amp;nbsp;their &lt;code&gt;Dockerfiles&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Dockerfile from&amp;nbsp;scratch&lt;/h1&gt;
&lt;p&gt;The ideal container image contains the application and the application&amp;#8217;s
dependencies and &lt;em&gt;nothing else&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Kelsey Hightower &lt;a href="https://www.youtube.com/watch?v=U6SfRPwTKqo"&gt;shows how to build such a container image&lt;/a&gt; for
an application&amp;nbsp;called &lt;code&gt;weather-data-collector&lt;/code&gt; using the&amp;nbsp;following
&lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;scratch&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;weather-data-collector&lt;span class="w"&gt; &lt;/span&gt;.
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/weather-data-collector&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This copies the application&amp;#8217;s locally built executable on the image&amp;#8217;s
file system.  The image contains no shell, no package manager, no additional
libraries.  Both image size and its the attack surface is minimal.  This
technique does work and creates an ideal container image and does solve all the
issues raised in the previous&amp;nbsp;section.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s a limitation though:&amp;nbsp;this &lt;code&gt;Dockerfile&lt;/code&gt; assumes that the application is
built as a single, statically linked&amp;nbsp;binary.&lt;/p&gt;
&lt;p&gt;Also, by reading&amp;nbsp;this &lt;code&gt;Dockerfile&lt;/code&gt; we don&amp;#8217;t know anything about provenance of
the application&amp;#8217;s binary: which build commands were executed, which tool chain
version is used, what additional libraries were installed before building.  To
remedy this it&amp;#8217;s common to use &lt;a href="https://github.com/kelseyhightower/helloworld/blob/master/Dockerfile"&gt;multi-stage Dockerfiles&lt;/a&gt;.
The first stage prepares the build environment and builds the application&amp;#8217;s
binary.  Then, during second stage, the binary is copied into an independent&amp;nbsp;layer.&lt;/p&gt;
&lt;p&gt;Multi-stage builds may work well for you if you always run the application in
containers, even during development.  In my experience, however, the build
instructions in the Dockerfile quickly become the duplicate of the project&amp;#8217;s
native build&amp;nbsp;instructions.&lt;/p&gt;
&lt;h1&gt;Blame your build&amp;nbsp;system&lt;/h1&gt;
&lt;p&gt;I don&amp;#8217;t believe that writing&amp;nbsp;a &lt;code&gt;Dockerfile&lt;/code&gt; is inherently bad.  I think the
underlying problem is that our build systems do a poor job of capturing our
application&amp;#8217;s dependencies.  The&amp;nbsp;various &lt;code&gt;Dockerfile&lt;/code&gt; tricks are just
workarounds for the absence of proper dependency&amp;nbsp;management.&lt;/p&gt;
&lt;p&gt;Take a look at &lt;em&gt;any&lt;/em&gt; non-trivial project&amp;#8217;s build instructions.  I bet you&amp;#8217;ll
find a getting started guide with a long list of tools and libraries to install
&lt;em&gt;before&lt;/em&gt; you can invoke the project&amp;#8217;s build&amp;nbsp;system.&lt;/p&gt;
&lt;p&gt;This is admitting that the project&amp;#8217;s dependency lists are incomplete and you
need out-of-band manipulations such as installing a package or downloading
something else from the&amp;nbsp;Internet.&lt;/p&gt;
&lt;h1&gt;Container images with&amp;nbsp;Nix&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://thewagner.net/blog/2020/04/30/exploring-nix/"&gt;Nix&lt;/a&gt; was explicitly designed to
capture &lt;em&gt;all&lt;/em&gt; dependencies of a software component.  This makes it a great fit
for building ideal container images which contain the application, the
application&amp;#8217;s dependencies and &lt;em&gt;nothing else&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To demonstrate, here&amp;#8217;s an example which packages the &lt;span class="caps"&gt;HTML&lt;/span&gt; pages of this blog
and a web server into a container&amp;nbsp;image.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;containerImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; pkgs&lt;span class="o"&gt;.&lt;/span&gt;dockerTools&lt;span class="o"&gt;.&lt;/span&gt;buildLayeredImage
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;thewagner.net&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="ss"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; pkgs&lt;span class="o"&gt;.&lt;/span&gt;python3 htmlPages &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="ss"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;Cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;python3&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bin/python&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-m&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;http.server&amp;quot;&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;--directory&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;htmlPages&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
      &lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="ss"&gt;ExposedPorts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;8000/tcp&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can run the built image&amp;nbsp;yourself:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;docker run -p 8000:8000 wagdav/thewagner.net
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you&amp;nbsp;visit &lt;code&gt;http://localhost:8000&lt;/code&gt; you can read my articles served from the
locally running&amp;nbsp;container.&lt;/p&gt;
&lt;p&gt;This &lt;a href="https://github.com/wagdav/thewagner.net/blob/fcda05cf33ca24ed97a0a71a9139de72ecdc90c9/flake.nix#L52-L75"&gt;snippet&lt;/a&gt; calls the&amp;nbsp;function &lt;code&gt;buildLayeredImage&lt;/code&gt; from the &lt;a href="https://github.com/NixOS/nixpkgs"&gt;Nix
Packages Collection&lt;/a&gt; to build the container image.  The function&amp;#8217;s
arguments define the image&amp;#8217;s name, contents and its configuration according to
the &lt;a href="https://opencontainers.org"&gt;&lt;span class="caps"&gt;OCI&lt;/span&gt;&lt;/a&gt; specification.  The function returns a derivation which builds a
container image containing the Python interpreter, for the web server, and the
static pages of my&amp;nbsp;blog.&lt;/p&gt;
&lt;p&gt;In short, you list the components you want in the image and Nix copies those
and their dependencies into the image archive.  Perhaps this summary sounds
underwhelming, but proper dependency management renders the building of the
container images conceptually simpler.  Instructions in&amp;nbsp;a &lt;code&gt;Dockerfile&lt;/code&gt; are
analogous to a shell script provisioning a freshly installed computer.  The Nix
expression looks like creating a compressed archive specifying a list of&amp;nbsp;files.&lt;/p&gt;
&lt;p&gt;To&amp;nbsp;use &lt;code&gt;buildLayeredimage&lt;/code&gt; you must have a Nix expression to build your
application. The &lt;a href="https://nixos.org/manual/nixpkgs/stable/#chap-language-support"&gt;Nixpkgs manual&lt;/a&gt; has a long section on
building packages for various programming&amp;nbsp;languages.&lt;/p&gt;
&lt;p&gt;Concretely, for the example showed in this section,  you can find the complete
definition&amp;nbsp;of &lt;code&gt;htmlPages&lt;/code&gt; &lt;a href="https://github.com/wagdav/thewagner.net/blob/fcda05cf33ca24ed97a0a71a9139de72ecdc90c9/flake.nix#L23-L39"&gt;here&lt;/a&gt;.  Everything is built from source
and&amp;nbsp;the &lt;code&gt;pkgs&lt;/code&gt; attribute set points to a specific commit of the &lt;a href="https://github.com/NixOS/nixpkgs"&gt;Nix Packages
collection&lt;/a&gt;. The image is reproducible: no software version changes
between builds unless explicitly&amp;nbsp;updated.&lt;/p&gt;
&lt;p&gt;As a bonus, this image is automatically built by &lt;a href="https://github.com/wagdav/thewagner.net/blob/fcda05cf33ca24ed97a0a71a9139de72ecdc90c9/.github/workflows/test.yml#L22"&gt;GitHub
Actions&lt;/a&gt; every time I push new content in the source repository.
And this works without fiddling with &lt;a href="https://github.com/marketplace/actions/build-and-push-docker-images"&gt;&lt;span class="caps"&gt;QEMU&lt;/span&gt;, BuildX and Docker&lt;/a&gt; or
using a special &lt;a href="https://circleci.com/docs/2.0/building-docker-images/"&gt;remote Docker&lt;/a&gt;&amp;nbsp;setup.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Dockerfiles, when used naively, yield bloated container images with
non-deterministic content.  The various techniques such as building static
executables and using multi-staged builds are just workarounds for the absence
of a programming language independent build system which is capable of
capturing all dependencies of an&amp;nbsp;application.&lt;/p&gt;
&lt;p&gt;Using Nix and the Nix Packages Collection it&amp;#8217;s possible to build minimal,
reproducible container images with a few lines of code which run locally and on
any hosted build automation&amp;nbsp;system.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Year 2020 in review</title><link href="https://thewagner.net/blog/2020/12/31/year-2020-in-review/" rel="alternate"/><published>2020-12-31T00:00:00+01:00</published><updated>2020-12-31T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2020-12-31:/blog/2020/12/31/year-2020-in-review/</id><summary type="html">&lt;p&gt;This blog has no specific theme,  I write about topics that are on my mind at
the moment.  In this post I reconstruct a story arc of the year and link to
articles I wrote in&amp;nbsp;2020.&lt;/p&gt;
&lt;p&gt;During the holiday break in 2019 I wrote about &lt;a href="https://thewagner.net/blog/2019/12/20/functions-in-disguise/"&gt;functions in
disguise&lt;/a&gt;.  I …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This blog has no specific theme,  I write about topics that are on my mind at
the moment.  In this post I reconstruct a story arc of the year and link to
articles I wrote in&amp;nbsp;2020.&lt;/p&gt;
&lt;p&gt;During the holiday break in 2019 I wrote about &lt;a href="https://thewagner.net/blog/2019/12/20/functions-in-disguise/"&gt;functions in
disguise&lt;/a&gt;.  I argued that we should use pure functions in software
configuration files instead of letting them develop idiosyncratic concepts and
custom&amp;nbsp;rules.&lt;/p&gt;
&lt;p&gt;I was particularly frustrated by the configuration of build automation systems
(also called continuous integration, continuous delivery systems).  In January
I was researching the &lt;a href="https://thewagner.net/blog/2020/01/07/the-essence-of-a-cicd-pipeline/"&gt;essence of a software delivery pipeline&lt;/a&gt; and I
picked on the concepts of some popular tools.  I argued that a software
delivery pipeline could be viewed as a function without introducing other,
ambiguous concepts.  To validate this idea I wrote &lt;a href="https://thewagner.net/blog/2020/10/18/kevlar/"&gt;Kevlar&lt;/a&gt;, an
experimental build automation system where pipelines are functions.  In Kevlar,
&lt;a href="https://thewagner.net/blog/2020/02/29/parallel-mindset/"&gt;contrary to many of our tools&lt;/a&gt;, parallelism is completely&amp;nbsp;automatic.&lt;/p&gt;
&lt;p&gt;While thinking about software delivery pipelines I &lt;a href="https://thewagner.net/blog/2020/04/30/exploring-nix/"&gt;discovered Nix&lt;/a&gt; which
now I use to configure all computers in my &lt;a href="https://thewagner.net/blog/2020/05/31/homelab/"&gt;homelab&lt;/a&gt;.  Using Nix I
made this blog&amp;#8217;s deployment &lt;a href="https://thewagner.net/blog/2020/07/03/deploying-thewagnernet/"&gt;automatic&lt;/a&gt; and
&lt;a href="https://thewagner.net/blog/2020/12/06/deploying-with-github-actions-and-more-nix/"&gt;reproducible&lt;/a&gt;. I believe Nix is the best tool today for
configuring physical machines and for building software delivery&amp;nbsp;pipelines.&lt;/p&gt;
&lt;p&gt;In the second part of the year I&amp;#8217;ve been learning Rust. I explored its
&lt;a href="https://thewagner.net/blog/2020/07/10/concurrency-in-go-clojure-haskell-and-rust/"&gt;concurrency primitives&lt;/a&gt; and in December I completed the &lt;a href="https://thewagner.net/blog/2020/12/25/advent-of-code-2020/"&gt;Advent
of Code&lt;/a&gt; in Rust&amp;nbsp;too.&lt;/p&gt;
&lt;p&gt;In summary, the articles I wrote over the past year fall in three broad&amp;nbsp;categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Concepts and configuration of build automation&amp;nbsp;software&lt;/li&gt;
&lt;li&gt;Infrastructure and&amp;nbsp;Nix&lt;/li&gt;
&lt;li&gt;Learning the Rust&amp;nbsp;language&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Looking forward to seeing what 2021&amp;nbsp;brings!&lt;/p&gt;
&lt;p&gt;Happy New&amp;nbsp;Year!&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Advent of Code 2020</title><link href="https://thewagner.net/blog/2020/12/25/advent-of-code-2020/" rel="alternate"/><published>2020-12-25T00:00:00+01:00</published><updated>2020-12-25T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2020-12-25:/blog/2020/12/25/advent-of-code-2020/</id><summary type="html">&lt;p&gt;Solving the Advent of Code 2020 puzzles in&amp;nbsp;Rust.&lt;/p&gt;</summary><content type="html">&lt;p&gt;This year I participated the first time in the &lt;a href="https://adventofcode.com/"&gt;Advent of
Code&lt;/a&gt;, a series of programming puzzles before
Christmas.  This post is an experience report of my 25+ day journey in&amp;nbsp;December.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: If you&amp;#8217;re still working or planning to work on the puzzles
stop reading&amp;nbsp;now.&lt;/p&gt;
&lt;h1&gt;Puzzles&lt;/h1&gt;
&lt;p&gt;From December 1 to December 25, a programming puzzle appears each day at Advent
of Code website.  To understand each day&amp;#8217;s two-part puzzle, go to the website
and read the full description (for example &lt;a href="https://adventofcode.com/2020/day/1"&gt;Day 1: Report
Repair&lt;/a&gt;).&lt;/p&gt;
&lt;h1&gt;Setup&lt;/h1&gt;
&lt;p&gt;I decided to write all solutions in Rust because I wanted to learn the
language.  This was my only &amp;#8220;hard&amp;#8221; requirement, the rest was just to have fun.
After solving the first couple of puzzles I set the following boundaries for&amp;nbsp;myself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Language&lt;/em&gt;: I write the solutions in Rust with minimal external dependencies.
  I used only the &lt;a href="https://docs.rs/regex"&gt;regex&lt;/a&gt; and
  &lt;a href="https://docs.rs/itertools"&gt;itertools&lt;/a&gt;&amp;nbsp;crates.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Independent programs&lt;/em&gt;: Each day&amp;#8217;s solution is a separate, independent
  executable with no code reuse among the&amp;nbsp;solutions.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Tests&lt;/em&gt;: I always transform the provided examples into automated tests.
  Sometimes I add more tests, but I&amp;#8217;m not strict about them.  &lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/.github/workflows/test.yml"&gt;GitHub
  Actions&lt;/a&gt; run the tests on every&amp;nbsp;commit.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Explore&lt;/em&gt;: I rewrite code as I learn new features of the Rust language and
  its standard library.  The code what you see now in the &lt;a href="https://github.com/wagdav/advent-of-code-2020"&gt;GitHub
  repository&lt;/a&gt; is often not my first&amp;nbsp;attempt.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also decided what were &lt;em&gt;not&lt;/em&gt; my&amp;nbsp;goals:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;No code golf&lt;/em&gt;: I wanted readable and concise solutions, but in no way I
  tried to minimize the lines of source&amp;nbsp;code.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Coding speed&lt;/em&gt;: I had no ambition (or chance) competing on the global
  leaderboard.  I solved the problems at my own speed, next to my full-time
  job.  Often it took me days to finish a&amp;nbsp;puzzle.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Code performance&lt;/em&gt;:  I didn&amp;#8217;t measure or optimize my code&amp;#8217;s performance
  in any way.  Nevertheless, the execution time of every solution is less than
  a few&amp;nbsp;seconds.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Highlights&lt;/h1&gt;
&lt;p&gt;Variations on &lt;a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life"&gt;Conway&amp;#8217;s Game of Life&lt;/a&gt; appeared on multiple days: on &lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day11.rs"&gt;day
11&lt;/a&gt; the cells evolved on a fixed grid, on &lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day17.rs"&gt;day 17&lt;/a&gt; in three and
four dimensions, and on &lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day24.rs"&gt;day 24&lt;/a&gt; the solution was expected on a
hexagonal grid.  I enjoyed these problems and learned a lot about Rust
iterators and iterator&amp;nbsp;adapters.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day18.rs"&gt;Day 18&lt;/a&gt; was about a small expression evaluator with custom precedence
and associativity rules.  I learned about &lt;a href="https://en.wikipedia.org/wiki/Shunting-yard_algorithm"&gt;Dijkstra&amp;#8217;s shunting yard
algorithm&lt;/a&gt; and I used it to transform the expressions specified
in infix notation to reverse Polish&amp;nbsp;notation.&lt;/p&gt;
&lt;p&gt;The second part of the puzzle on &lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day13.rs"&gt;day 13&lt;/a&gt; caused me headaches.
Someone on a Reddit thread suggested that the &lt;a href="https://en.wikipedia.org/wiki/Chinese_remainder_theorem"&gt;Chinese remainder
theorem&lt;/a&gt; is relevant here.  I learned the basics of this theorem
and recognized how to use it in the&amp;nbsp;solution.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day10.rs"&gt;Day 10&lt;/a&gt; took me multiple days to finish.  I failed recognize that
relevant strategy to solve this puzzle was &lt;a href="https://en.wikipedia.org/wiki/Dynamic_programming"&gt;dynamic programming&lt;/a&gt; on
which &lt;a href="https://thewagner.net/blog/2018/04/30/minimum-coin-exchange/"&gt;I even wrote an article&lt;/a&gt;.
Perhaps I should read it&amp;nbsp;again&amp;#8230;&lt;/p&gt;
&lt;h1&gt;In the&amp;nbsp;weeds&lt;/h1&gt;
&lt;p&gt;There were also days when the problem itself was not particularly difficult,
but I still struggled.  On these days I ended up with code that sort of works,
but not particularly&amp;nbsp;nice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day19.rs"&gt;Day 19&lt;/a&gt;: The problem input represented a language akin to regular
  expressions.  My parsing code became quite messy, maybe I should have used
  actual regular expressions to parse the input&amp;nbsp;file.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day20.rs"&gt;Day 20&lt;/a&gt;: I made many mistakes during the implementation, the solution
  was tedious with much bookkeeping and little&amp;nbsp;reward.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day21.rs"&gt;Day 21&lt;/a&gt;: I couldn&amp;#8217;t connect to the problem because I found it too
  convoluted.  After I looked at other people&amp;#8217;s solution it was clear that I
  was missing the underlying search algorithm therefore my implementation
  turned out to be less than&amp;nbsp;great.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Learning&amp;nbsp;Rust&lt;/h1&gt;
&lt;p&gt;Solving these puzzles was great for learning Rust. From these last three weeks
I&amp;#8217;d underline these&amp;nbsp;topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Cargo&lt;/em&gt;: The cargo package manager works well and easy to use. The project
  was easy to start and the file layout is clear and&amp;nbsp;simple.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Testing&lt;/em&gt;: Rust has a built-in testing framework that integrates well with
  cargo.  It&amp;#8217;s easy to add tests and maintain tests because the test code is
  close to the application&amp;nbsp;code.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Cargo watch&lt;/em&gt;: &lt;a href="https://github.com/passcod/cargo-watch"&gt;Cargo Watch&lt;/a&gt; can run
  the tests every time a change occurs in  project&amp;#8217;s source.  I only introduced
  this tool at &lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day16.rs"&gt;day 16&lt;/a&gt;. I should have done it right at the&amp;nbsp;beginning.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Vec&lt;/em&gt;: For almost every puzzle I used
  &lt;a href="https://doc.rust-lang.org/std/vec/struct.Vec.html"&gt;Vec&lt;/a&gt; from the standard&amp;nbsp;library.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Iterators&lt;/em&gt;: I learned to use methods of the
  &lt;a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html"&gt;Iterator&lt;/a&gt; trait. I&amp;nbsp;used &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;count&lt;/code&gt; almost every day.  Long iterator chains take a
  bit of getting used to, but they are idiomatic in&amp;nbsp;Rust.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;itertools crate&lt;/em&gt;: &lt;code&gt;multi_cartesian_product&lt;/code&gt; from the
  &lt;a href="https://docs.rs/itertools"&gt;itertools&lt;/a&gt; crate was a life-saver for
  implementing Game of Life in arbitrary&amp;nbsp;dimensions.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Regex crate&lt;/em&gt;:  Well, regular expressions are just&amp;nbsp;everywhere.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;enum&lt;/em&gt;: In&amp;nbsp;Rust &lt;code&gt;enum&lt;/code&gt; is a real sum type where the variants can contain data
  too. I used&amp;nbsp;an &lt;code&gt;enum&lt;/code&gt; as a central type on days &lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day04.rs"&gt;4&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day08.rs"&gt;8&lt;/a&gt;,
  &lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day14.rs"&gt;14&lt;/a&gt;, &lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day18.rs"&gt;18&lt;/a&gt; and &lt;a href="https://github.com/wagdav/advent-of-code-2020/blob/main/src/bin/day19.rs"&gt;19&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Completing the Advent of Code and learning a new programming language was
challenging.  I learned a lot in these last 25 days about puzzles, algorithms
and about the Rust&amp;nbsp;language.&lt;/p&gt;
&lt;p&gt;I particularly enjoyed the puzzles where &lt;a href="https://thewagner.net/blog/2018/03/10/knowing-algorithms/"&gt;knowing an
algorithm&lt;/a&gt; is rewarding and makes your code
concise and readable.  When my code is long and messy I know that I&amp;#8217;m missing
something: a data structure, an algorithm or a language feature.  The hard part
is to figure out which&amp;nbsp;one.&lt;/p&gt;
&lt;p&gt;The source code of all solutions are available on &lt;a href="https://github.com/wagdav/advent-of-code-2020"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Acknowledgment&lt;/h1&gt;
&lt;p&gt;Thanks &lt;a href="https://twitter.com/ericwastl"&gt;Eric Wastl&lt;/a&gt; for creating and running
&lt;a href="https://adventofcode.com"&gt;Advent of Code&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Deploying with GitHub Actions and more Nix</title><link href="https://thewagner.net/blog/2020/12/06/deploying-with-github-actions-and-more-nix/" rel="alternate"/><published>2020-12-06T00:00:00+01:00</published><updated>2020-12-06T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2020-12-06:/blog/2020/12/06/deploying-with-github-actions-and-more-nix/</id><summary type="html">&lt;p&gt;In July I described how I use Travis &lt;span class="caps"&gt;CI&lt;/span&gt; to deploy this static site to GitHub
Pages using a Nix pipeline.  Before continuing I suggest reading &lt;a href="/blog/2020/07/03/deploying-thewagnernet/"&gt;that
article&lt;/a&gt; because rest of this post builds on top of&amp;nbsp;that.&lt;/p&gt;
&lt;p&gt;This article is about the changes I made in this blog&amp;#8217;s …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In July I described how I use Travis &lt;span class="caps"&gt;CI&lt;/span&gt; to deploy this static site to GitHub
Pages using a Nix pipeline.  Before continuing I suggest reading &lt;a href="/blog/2020/07/03/deploying-thewagnernet/"&gt;that
article&lt;/a&gt; because rest of this post builds on top of&amp;nbsp;that.&lt;/p&gt;
&lt;p&gt;This article is about the changes I made in this blog&amp;#8217;s deployment process
during the last months. These include switching to Nix Flakes, adding more
checks to the pipeline and moving from Travis &lt;span class="caps"&gt;CI&lt;/span&gt; to GitHub&amp;nbsp;Actions.&lt;/p&gt;
&lt;h1&gt;Flakes&lt;/h1&gt;
&lt;p&gt;Flakes are an experimental mechanism to package Nix expressions into composable
entities.  Flakes define a standard structure of Nix projects for hermetic and
reproducible&amp;nbsp;evaluation.&lt;/p&gt;
&lt;p&gt;The blog is still built using Nix, but now the entry point is
&lt;a href="https://github.com/wagdav/thewagner.net/blob/efa3d5b5f62/flake.nix"&gt;flake.nix&lt;/a&gt;.  The heart of this expression is a
&lt;a href="https://thewagner.net/blog/2020/01/07/the-essence-of-a-cicd-pipeline/"&gt;function&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; self&lt;span class="p"&gt;,&lt;/span&gt; inputs&lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;checks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;
  &lt;span class="ss"&gt;modules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;
  &lt;span class="ss"&gt;packages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;
  &lt;span class="o"&gt;..&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The&amp;nbsp;function &lt;code&gt;outputs&lt;/code&gt; takes the project&amp;#8217;s external dependencies as inputs and
returns the build artifacts in a record.  Build artifacts can be Nix packages,
NixOS modules, test results, container images, virtual machine images.
Basically anything Nix can build.  We&amp;#8217;ll see a concrete example of&amp;nbsp;the &lt;code&gt;checks&lt;/code&gt;
attribute in subsequent section.  There&amp;#8217;s an ongoing effort to define a
standard structure for the returned value so that specific tools can understand
and use the built&amp;nbsp;derivations.&lt;/p&gt;
&lt;p&gt;The source tree also contains a lock file &lt;a href="https://github.com/wagdav/thewagner.net/blob/efa3d5b5f62/flake.lock"&gt;flake.lock&lt;/a&gt; to ensure
that pages of this blog are always built with &lt;em&gt;exactly&lt;/em&gt; the same set of tools
independently where the build is executed.  The same environment is used on my
workstation, on yours, on a worker of a hosted &lt;span class="caps"&gt;CI&lt;/span&gt;&amp;nbsp;system.&lt;/p&gt;
&lt;p&gt;To learn more about Flakes I recommend the following&amp;nbsp;resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presentation by Eelco Dolstra at NixCon 2019 (&lt;a href="https://www.youtube.com/watch?v=UeBX7Ide5a0"&gt;Youtube&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Three-part series on Tweag&amp;#8217;s technical blog (&lt;a href="https://www.tweag.io/blog/2020-05-25-flakes/"&gt;part 1&lt;/a&gt;,
  &lt;a href="https://www.tweag.io/blog/2020-06-25-eval-cache/"&gt;part 2&lt;/a&gt;, &lt;a href="https://www.tweag.io/blog/2020-07-31-nixos-flakes/"&gt;part 3&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;RFC&lt;/span&gt; documenting the flake&amp;#8217;s structure (&lt;a href="https://github.com/tweag/rfcs/blob/flakes/rfcs/0049-flakes.md"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Compatibility&lt;/h1&gt;
&lt;p&gt;Currently flakes are unstable and experimental in Nix. You need to explicitly
enable flake support if you want to use them. The repository
&lt;a href="https://github.com/edolstra/flake-compat"&gt;flake-compat&lt;/a&gt; provides a compatibility function to allow flakes
to be used by non-flake-enabled Nix&amp;nbsp;versions.&lt;/p&gt;
&lt;p&gt;If you &lt;a href="https://nixos.org/download.html"&gt;install the Nix package manager&lt;/a&gt; on
your platform and clone the repository you can build the static pages of this
site by&amp;nbsp;running &lt;code&gt;nix-build&lt;/code&gt; in the source&amp;nbsp;tree.&lt;/p&gt;
&lt;p&gt;With a flake-enabled, experimental Nix version you can even build the project
without cloning, directly referencing the repository on&amp;nbsp;GitHub:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;nix build github:wagdav/thewagner.net&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Building the static pages of this blog has no practical use for anybody but me.
But imagine if your favorite project would build on your machine without
installing &lt;em&gt;anything&lt;/em&gt; but one standalone&amp;nbsp;binary?&lt;/p&gt;
&lt;p&gt;Language-specific package managers such&amp;nbsp;as &lt;code&gt;cargo&lt;/code&gt;, &lt;code&gt;go get&lt;/code&gt;, &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;pip&lt;/code&gt; work
well if your project uses &lt;em&gt;only&lt;/em&gt; that specific language.  The reality is that
even the simplest projects, such as the source code of this blog, may require
tools from &lt;em&gt;any&lt;/em&gt; language&amp;nbsp;ecosystems.&lt;/p&gt;
&lt;h1&gt;Checks&lt;/h1&gt;
&lt;p&gt;The &lt;code&gt;checks&lt;/code&gt; attribute of the structure returned by the&amp;nbsp;flake&amp;#8217;s &lt;code&gt;outputs&lt;/code&gt;
function describes self-tests.  For this blog&amp;#8217;s source the checks look like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ss"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; self&lt;span class="p"&gt;,&lt;/span&gt; nixpkgs &lt;span class="p"&gt;}:&lt;/span&gt;
  checks&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;x86_64-linux&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="ss"&gt;build&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; self&lt;span class="o"&gt;.&lt;/span&gt;defaultPackage&lt;span class="o"&gt;.&lt;/span&gt;x86_64-linux&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="ss"&gt;shellcheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; pkgs&lt;span class="o"&gt;.&lt;/span&gt;runCommand &lt;span class="s2"&gt;&amp;quot;shellcheck&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="ss"&gt;markdownlint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; pkgs&lt;span class="o"&gt;.&lt;/span&gt;runCommand &lt;span class="s2"&gt;&amp;quot;mdl&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="ss"&gt;yamllint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; pkgs&lt;span class="o"&gt;.&lt;/span&gt;runCommand &lt;span class="s2"&gt;&amp;quot;yamllint&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The checks are grouped per supported platform, in this case there&amp;#8217;s only&amp;nbsp;one:
&lt;code&gt;x86_64-linux&lt;/code&gt;.  For this blog&amp;#8217;s source &lt;em&gt;checking&lt;/em&gt;&amp;nbsp;means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build the static the blog&amp;#8217;s static &lt;span class="caps"&gt;HTML&lt;/span&gt;&amp;nbsp;files&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;shellcheck&lt;/code&gt; on all scripts in the source&amp;nbsp;code&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;mdl&lt;/code&gt; on all markdown files in the source&amp;nbsp;code&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;yamllint&lt;/code&gt; on all &lt;span class="caps"&gt;YAML&lt;/span&gt; files in the source&amp;nbsp;code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If any of these steps fail, the project is considered broken. You can see the
full code &lt;a href="https://github.com/wagdav/thewagner.net/blob/efa3d5b5f62/flake.nix"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you use the experimental Nix version with flake support you can execute all
the checks with the following&amp;nbsp;command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;nix flake check  # using Nix experimental&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or with stable Nix without&amp;nbsp;flake-support:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;nix-build -a checks.x86_64-linux  # using Nix stable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Again, running the checks only requires the Nix package manager to be&amp;nbsp;installed.&lt;/p&gt;
&lt;h1&gt;GitHub&amp;nbsp;Actions&lt;/h1&gt;
&lt;p&gt;Previously the build and deployment scripts ran on Travis &lt;span class="caps"&gt;CI&lt;/span&gt;.  I was curious to
see how the deployment would work on GitHub Actions, which has become popular
during the past&amp;nbsp;year.&lt;/p&gt;
&lt;p&gt;The transition from Travis &lt;span class="caps"&gt;CI&lt;/span&gt; to GitHub Actions was trivial.  The &lt;a href="https://github.com/wagdav/thewagner.net/blob/efa3d5b5f62/.github/workflows/test.yml"&gt;workflow
definition&lt;/a&gt; contains the minimal required boilerplate.  21 lines
specify the following&amp;nbsp;steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check out the&amp;nbsp;repository&lt;/li&gt;
&lt;li&gt;Install Nix using Cachix&amp;#8217;s
  &lt;a href="https://github.com/cachix/install-nix-action"&gt;install-nix-action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Run the&amp;nbsp;checks&lt;/li&gt;
&lt;li&gt;Deploy the site if on the master&amp;nbsp;branch&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The workflow is not concerned with installing or configuring anything but Nix
and it&amp;#8217;s merely coordinating the build and deploy&amp;nbsp;steps.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I use a Nix expression to build the static pages of my blog.  The build runs
locally and on the workers of hosted &lt;span class="caps"&gt;CI&lt;/span&gt;/&lt;span class="caps"&gt;CD&lt;/span&gt; systems such as GitHub Actions and
Travis &lt;span class="caps"&gt;CI&lt;/span&gt;.  The build requires no external dependencies other than the Nix
package manager.  The build is reproducible and hermetic: no matter where the
project is built, which packages are installed, the result is always the same&amp;nbsp;everywhere.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Kevlar</title><link href="https://thewagner.net/blog/2020/10/18/kevlar/" rel="alternate"/><published>2020-10-18T00:00:00+02:00</published><updated>2020-10-18T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2020-10-18:/blog/2020/10/18/kevlar/</id><summary type="html">&lt;p&gt;Previously, I distilled the &lt;a href="https://thewagner.net/blog/2020/01/07/the-essence-of-a-cicd-pipeline/"&gt;essence of a software delivery
pipeline&lt;/a&gt; and argued
that a transformation step that builds or tests a piece of code can be viewed
as a function.  Functions compose according to well-defined mathematical rules
and they are a suitable model for defining arbitrary pipelines.  Instead of
talking …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Previously, I distilled the &lt;a href="https://thewagner.net/blog/2020/01/07/the-essence-of-a-cicd-pipeline/"&gt;essence of a software delivery
pipeline&lt;/a&gt; and argued
that a transformation step that builds or tests a piece of code can be viewed
as a function.  Functions compose according to well-defined mathematical rules
and they are a suitable model for defining arbitrary pipelines.  Instead of
talking about build tasks, jobs, stages and workflows, the build pipeline could
be a function that takes the source code as argument and returns build&amp;nbsp;artifacts.&lt;/p&gt;
&lt;p&gt;In this article I describe, Kevlar, an experimental build automation tool that
tries to build on these&amp;nbsp;concepts.&lt;/p&gt;
&lt;h1&gt;Programming in &lt;span class="caps"&gt;YAML&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;For almost two years I was part of a team building a build automation system
for &lt;a href="https://pix4d.com"&gt;Pix4D&lt;/a&gt;, a medium-sized organization&amp;nbsp;with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Few dozen&amp;nbsp;developers&lt;/li&gt;
&lt;li&gt;Handful of&amp;nbsp;projects&lt;/li&gt;
&lt;li&gt;Couple of programming&amp;nbsp;languages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We wanted a system to build our software products on all the major desktop
and mobile platforms.  A few years back when the project started the scene of
managed build automation tools was less exiting than today: Travis &lt;span class="caps"&gt;CI&lt;/span&gt; was a a
major player, GitLab was on the rise, GitHub Actions and CircleCI didn&amp;#8217;t&amp;nbsp;exist.&lt;/p&gt;
&lt;p&gt;For various reasons we ruled out the available hosted options and we deployed
&lt;a href="https://concourse-ci.org/"&gt;Concourse &lt;span class="caps"&gt;CI&lt;/span&gt;&lt;/a&gt; in our data centers.  Concourse
served us well: today Pix4D&amp;#8217;s continuous integration system builds more
libraries and products than ever.  Concourse uses &lt;span class="caps"&gt;YAML&lt;/span&gt; for describing its
pipelines which model the software delivery process.  And &lt;span class="caps"&gt;YAML&lt;/span&gt; started to
sprout&amp;nbsp;everywhere.&lt;/p&gt;
&lt;p&gt;Although &lt;span class="caps"&gt;YAML&lt;/span&gt; is used to configure virtually all build automation systems its
limitations become apparent when you write a pipeline for any reasonably
complex software project.  Using only numbers, strings, lists and associative
arrays pipeline definitions are verbose and&amp;nbsp;repetitive.&lt;/p&gt;
&lt;p&gt;To allow for reusing pipeline code build automation systems introduced ad-hoc
concepts and workarounds.  Some examples&amp;nbsp;are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://concourse-ci.org/config-basics.html#yaml-tips-and-tricks"&gt;&lt;span class="caps"&gt;YAML&lt;/span&gt;&amp;nbsp;anchors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/templates"&gt;Templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://circleci.com/docs/2.0/pipeline-variables/"&gt;Pipeline&amp;nbsp;Variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vito/oci-build-task"&gt;Reusable build&amp;nbsp;tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://circleci.com/orbs/"&gt;Orbs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many systems also provide control flow operators such as conditionals, loops
and other &lt;a href="https://circleci.com/blog/circleci-matrix-jobs/"&gt;special constructs&lt;/a&gt;
to express, for example, matrix builds.  Ultimately the pipeline configuration
becomes an &lt;a href="https://thewagner.net/blog/2019/12/20/functions-in-disguise/"&gt;implicitly functional programming
language&lt;/a&gt; using &lt;span class="caps"&gt;YAML&lt;/span&gt;&amp;#8217;s&amp;nbsp;syntax.&lt;/p&gt;
&lt;p&gt;In programming we reduce repetition using methods, functions and procedures.
We organize our code in modules and packages for sharing and reuse.  Let&amp;#8217;s try
to use these concepts to express software delivery&amp;nbsp;pipelines.&lt;/p&gt;
&lt;h1&gt;Enter&amp;nbsp;Kevlar&lt;/h1&gt;
&lt;p&gt;I found programming in &lt;span class="caps"&gt;YAML&lt;/span&gt; frustrating and I wanted to explore how a build
pipeline would look like in a general-purpose programming language.  &lt;a href="https://github.com/wagdav/kevlar"&gt;Project
Kevlar&lt;/a&gt; was&amp;nbsp;born.&lt;/p&gt;
&lt;p&gt;In Kevlar you express the build pipelines using Haskell functions. A step that
&lt;a href="https://github.com/wagdav/kevlar/blob/master/.kevlar/config.hs"&gt;builds Kevlar itself&lt;/a&gt; looks like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Kaniko&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;kevlar-builder&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;docker/kevlar-builder&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Need&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;./ci/build.sh&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Need&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function takes the source repository as a parameter and describes the
following&amp;nbsp;actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clone the source&amp;nbsp;repository.&lt;/li&gt;
&lt;li&gt;Run &lt;a href="https://github.com/GoogleContainerTools/kaniko"&gt;Kaniko&lt;/a&gt; to build a
  container image described in a Dockerfile of the source&amp;nbsp;repository.&lt;/li&gt;
&lt;li&gt;Start a container from the build image and execute the build&amp;nbsp;script.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;Need&lt;/code&gt; argument of the functions express data dependencies explicitly.  We
need the cloned repository to build the Docker image because&amp;nbsp;the &lt;code&gt;Dockerfile&lt;/code&gt;
is found there.  Similarly, because the build script is running in a container
it needs both the source code checked out and the container&amp;#8217;s image&amp;nbsp;built.&lt;/p&gt;
&lt;p&gt;The syntax may be unusual, but it&amp;#8217;s just regular Haskell code.  This could have
been easily written in &lt;span class="caps"&gt;YAML&lt;/span&gt; with equal clarity, so why bother with Haskell?
The advantages of using real programming language constructs appear when we
build more complicated workflows.  As pipelines grow we can factor out common
into helper functions or shared modules and&amp;nbsp;packages.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s continue building Kevlar&amp;#8217;s own pipeline by adding a publish&amp;nbsp;step:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Kaniko&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;kevlar-publish&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;docker/kevlar-publish&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Need&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;shell&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;./ci/publish.sh&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Need&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;build&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kt"&gt;Need&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kt"&gt;Secret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;GITHUB_ACCESS_TOKEN&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;publish&lt;/code&gt; function takes the address of the source repository and the build
binary. The steps are similar to that of&amp;nbsp;the &lt;code&gt;build&lt;/code&gt; function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clone the source&amp;nbsp;repository.&lt;/li&gt;
&lt;li&gt;Build a Docker image with the tools required for releasing the binary&amp;nbsp;artifacts.&lt;/li&gt;
&lt;li&gt;Start a container from the built image and execute the publish&amp;nbsp;script.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With&amp;nbsp;the &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;publish&lt;/code&gt; functions we can succinctly define Kevlar&amp;#8217;s
build-and-release&amp;nbsp;pipeline:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;buildAndPublish&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function, which&amp;nbsp;composes &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;publish&lt;/code&gt; using the monadic bind
operator, actually works it does what you&amp;#8217;d expect: the pipeline builds and
publishes the built binaries running both steps in dedicated Docker&amp;nbsp;containers.&lt;/p&gt;
&lt;p&gt;We may refer to the&amp;nbsp;functions &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;publish&lt;/code&gt; as &amp;#8220;steps&amp;#8221; and the&amp;nbsp;function
&lt;code&gt;buildAndPublish&lt;/code&gt; as the final &amp;#8220;pipeline&amp;#8221;.  In Kevlar they are all represented
as functions returning&amp;nbsp;a &lt;code&gt;Task&lt;/code&gt; value.&lt;/p&gt;
&lt;p&gt;The&amp;nbsp;function &lt;code&gt;buildAndPublish&lt;/code&gt; defines the following graph of&amp;nbsp;dependencies:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;           ↗ build image  → compile ↘
clone repo                            publish
           ↘        build image     ↗
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This figure reveals interesting optimization&amp;nbsp;opportunities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We could run the image building steps in parallel because they don&amp;#8217;t use each
  other&amp;#8217;s&amp;nbsp;output.&lt;/li&gt;
&lt;li&gt;We could avoid cloning the repository twice and reuse the repository&amp;#8217;s local
  copy in downstream&amp;nbsp;steps.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The next sections expand on these ideas in&amp;nbsp;detail.&lt;/p&gt;
&lt;h2&gt;Automatic&amp;nbsp;parallelism&lt;/h2&gt;
&lt;p&gt;Instead of naively executing each steps as they appear in the source code,
Kevlar uses as much parallelism as possible.  The user defines data
dependencies using&amp;nbsp;the &lt;code&gt;Need&lt;/code&gt; parameter and &lt;a href="https://thewagner.net/blog/2020/02/29/parallel-mindset/"&gt;parallelism is
automatic&lt;/a&gt;.  This idea is not
new: for example build systems like make and ninja track dependencies among
build steps and schedule as many of them as they can on the available&amp;nbsp;processors.&lt;/p&gt;
&lt;p&gt;Initially I built Kevlar on top of &lt;a href="https://github.com/ndmitchell/shake"&gt;Shake&lt;/a&gt;, a library for creating build
systems.  Shake is a well-designed and performant library but it was a poor fit
for Kevlar.  Shake takes the source code and builds your program&amp;#8217;s binary as
fast as possible.  Build rules and dependencies between tasks rely on file
names and file patterns.  I needed a library to express general data
dependencies in the pipeline code without using the file&amp;nbsp;system.&lt;/p&gt;
&lt;p&gt;I switched Kevlar to use &lt;a href="https://github.com/facebook/Haxl"&gt;Haxl&lt;/a&gt; to make parallelism automatic.  Haxl
relies on some algebraic properties of the program to identify data
dependencies between tasks and schedules many independent tasks concurrently.
The &lt;a href="https://www.youtube.com/watch?v=sT6VJkkhy0o"&gt;magic of Haxl&lt;/a&gt; is contained within its own codebase and  I only
had to implement a &lt;a href="https://github.com/wagdav/kevlar/blob/master/src/Kevlar/LocalExecutor/DataSource.hs"&gt;custom data source&lt;/a&gt;.  Even better, the
user, in this case the pipeline author, doesn&amp;#8217;t need to be aware of any of this
and the pipeline remains a regular Haskell&amp;nbsp;function.&lt;/p&gt;
&lt;p&gt;Today&amp;#8217;s popular build automation systems require the user to explicitly choose
between sequential or parallel execution when designing the pipeline.  Concepts
like tasks, steps, jobs are introduced with an emphasis of execution order
instead of &lt;a href="https://thewagner.net/blog/2020/01/07/the-essence-of-a-cicd-pipeline/"&gt;capturing the
meaning&lt;/a&gt; of the
transformation steps in the software delivery&amp;nbsp;process.&lt;/p&gt;
&lt;p&gt;In Kevlar the user is only concerned with data dependencies.  The system makes
sure that the pipeline&amp;#8217;s task run in the right order as fast as&amp;nbsp;possible.&lt;/p&gt;
&lt;h2&gt;Incremental&amp;nbsp;work&lt;/h2&gt;
&lt;p&gt;Avoiding extra work is crucial for good performance.  The output of a given
task should be reused as the pipeline executes: the output might be available
from earlier steps or from earlier&amp;nbsp;executions.&lt;/p&gt;
&lt;p&gt;Reusing a result is desired if the pipeline fans out: we compute the result
once and copy it to the downstream tasks.  We&amp;#8217;ve seen an example of this in the
previous section where the repository&amp;#8217;s local copy was passed to start building
the two container images&amp;nbsp;independently.&lt;/p&gt;
&lt;p&gt;Reusing results from earlier executions is harder.  Tasks may return many kinds
of outputs: single files, directories, container images.  These all need to be
persisted somewhere to be reused during the next pipeline execution.  I
couldn&amp;#8217;t find a satisfactory solution to this in&amp;nbsp;Kevlar.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Frustrated by the verbose &lt;span class="caps"&gt;YAML&lt;/span&gt; configuration used by popular build automation
tools I wrote Kevlar, an experimental system, where the pipeline configuration
is expressed in a functional programming&amp;nbsp;language.&lt;/p&gt;
&lt;p&gt;Pipelines are functions which define data dependencies and not execution order.
With some help from great libraries parallelism is automatic and duplicate work
is&amp;nbsp;avoided.&lt;/p&gt;
&lt;p&gt;Working on Kevlar made me appreciate even more the power of pure functions:
values, functions and their combinations are powerful modeling tools.  When
thinking functionally you ask what things &lt;em&gt;are&lt;/em&gt; instead of what they &lt;em&gt;do&lt;/em&gt; and
this leads to interesting discoveries and simple, solid&amp;nbsp;designs.&lt;/p&gt;
&lt;p&gt;I also realized that I&amp;#8217;m rediscovering &lt;a href="https://thewagner.net/blog/2020/04/30/exploring-nix/"&gt;the basic principles of
Nix&lt;/a&gt; and Nix is so much better
than Kevlar ever wanted to be.  If the ideas in this article resonate with you
I recommend to try building your &lt;a href="https://thewagner.net/blog/2020/07/03/deploying-thewagnernet/"&gt;next software delivery pipeline with
Nix&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Acknowledgment&lt;/h1&gt;
&lt;p&gt;I dedicate this post to the memory of my friend and colleague Salah Missri who
tragically passed away earlier this year.  Salah was the biggest fan of Kevlar.
He patiently listened to me ranting about continuous integration systems and
encouraged me keep working on Kevlar until it reaches world&amp;nbsp;domination.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Concurrency in Go, Clojure, Haskell and Rust</title><link href="https://thewagner.net/blog/2020/07/10/concurrency-in-go-clojure-haskell-and-rust/" rel="alternate"/><published>2020-07-10T00:00:00+02:00</published><updated>2020-07-10T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2020-07-10:/blog/2020/07/10/concurrency-in-go-clojure-haskell-and-rust/</id><summary type="html">&lt;p&gt;In the past I wrote &lt;a href="https://thewagner.net/blog/2018/02/26/concurrency-patterns/"&gt;two&lt;/a&gt; &lt;a href="/blog/2019/07/15/concurrency-without-magic/"&gt;articles&lt;/a&gt; where I
explored concurrency in Haskell using some examples from the talk &lt;a href="https://talks.golang.org/2012/concurrency.slide"&gt;Go
Concurrency Patterns&lt;/a&gt; by Rob&amp;nbsp;Pike.&lt;/p&gt;
&lt;p&gt;The examples are different implementations of a simulated search engine which
receives a search query and returns web, image and video results.  The first
version …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In the past I wrote &lt;a href="https://thewagner.net/blog/2018/02/26/concurrency-patterns/"&gt;two&lt;/a&gt; &lt;a href="/blog/2019/07/15/concurrency-without-magic/"&gt;articles&lt;/a&gt; where I
explored concurrency in Haskell using some examples from the talk &lt;a href="https://talks.golang.org/2012/concurrency.slide"&gt;Go
Concurrency Patterns&lt;/a&gt; by Rob&amp;nbsp;Pike.&lt;/p&gt;
&lt;p&gt;The examples are different implementations of a simulated search engine which
receives a search query and returns web, image and video results.  The first
version sends the search queries sequentially.  Then, the program is gradually
improved to become concurrent and better&amp;nbsp;performing.&lt;/p&gt;
&lt;p&gt;Earlier I presented &lt;a href="https://thewagner.net/blog/2018/02/26/concurrency-patterns/"&gt;each step&lt;/a&gt; in detail.  Here I will only
show the final form of the fake search function in four different programming
languages: Go, Clojure, Haskell and&amp;nbsp;Rust.&lt;/p&gt;
&lt;h1&gt;Go&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://talks.golang.org/2012/concurrency.slide"&gt;Rob Pike&amp;#8217;s version&lt;/a&gt; of the search function executes the three kinds
of search queries concurrently and sends the search requests to replicated
back-end servers to reduce tail&amp;nbsp;latency.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://talks.golang.org/2012/concurrency.slide#50&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Web1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Web2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Image1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Image2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Video1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Video2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;After&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;timed out&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The implementation shows Go&amp;#8217;s concurrency primitives: goroutines, channels, and
the select statement.  The Go runtime manages the goroutines which are
lightweight threads of execution.  Goroutines communicate via channels.&amp;nbsp;The
&lt;code&gt;switch&lt;/code&gt; statement allows merging values originating from multiple channels.
These constructs are all built into the language, no external library is&amp;nbsp;required.&lt;/p&gt;
&lt;h1&gt;Clojure&lt;/h1&gt;
&lt;p&gt;I was surprised when Rich Hickey mentioned the fake search example in his
presentation on &lt;a href="https://www.youtube.com/watch?v=f6kdp27TYZs"&gt;Clojure core async&lt;/a&gt;.  I copied here the code
from the slides for&amp;nbsp;reference:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;;; https://www.youtube.com/watch?v=drmNlZVkUeE?t=2458&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;query&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;web1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;web2&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;image1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;image2&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;video1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;video2&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;loop &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="nv"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]]&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;= &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nv"&gt;ret&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;inc &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;conj &lt;/span&gt;&lt;span class="nv"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;alt!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)))))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Clojure&amp;#8217;s async library uses the same primitives as Go: the syntax is &lt;span class="caps"&gt;LISP&lt;/span&gt;, but
the structure of the program is identical to that of the Go version.  Watch
&lt;a href="https://www.youtube.com/watch?v=f6kdp27TYZs"&gt;Rich Hickey&amp;#8217;s presentation&lt;/a&gt; if you&amp;#8217;re interested how this
works on the &lt;span class="caps"&gt;JVM&lt;/span&gt; and in a web browser using&amp;nbsp;ClojureScript.&lt;/p&gt;
&lt;h1&gt;Haskell&lt;/h1&gt;
&lt;p&gt;My first implementation of the simulated search engine was in
&lt;a href="https://thewagner.net/blog/2018/02/26/concurrency-patterns/"&gt;Haskell&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;search30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;search30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maxDelay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mapConcurrently&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printResults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is my favorite version of this exercise because it&amp;#8217;s succint and
expressive.  We don&amp;#8217;t see the primitives we saw in the Go and Clojure version,
but an expression stating that some operations are expected to run
concurrently.  Writing this high-level code is possible because the threads are
managed by the Haskell run-time system and I&amp;#8217;m using the &lt;a href="https://hackage.haskell.org/package/async-2.1.0/docs/Control-Concurrent-Async.html"&gt;async&lt;/a&gt;
library which exposes a powerful, composable &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;h1&gt;Rust&lt;/h1&gt;
&lt;p&gt;My latest addition to this collection is &lt;a href="https://github.com/wagdav/rust-concurrency-patterns"&gt;written in Rust&lt;/a&gt;, a
language I&amp;#8217;ve been learning for the last couple of&amp;nbsp;weeks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;search30&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;SearchQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;SearchResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;from_millis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;tokio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;fastest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;SearchKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Web&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;fastest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;SearchKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;fastest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;SearchKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SearchResult&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unwrap_or_else&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SearchResult&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code looks similar to the Haskell version because we don&amp;#8217;t see channels
and explicit thread management here either.  The Rust language defines&amp;nbsp;the
&lt;code&gt;async/await&lt;/code&gt; syntax and the related interfaces but it delegates the concrete
execution strategy to external libraries.  In this example I chose the
&lt;a href="https://tokio.rs/"&gt;Tokio&lt;/a&gt; library which is a mature asynchronous run-time library, but
in the future I&amp;#8217;d like to explore other libraries too and learn more about how
they&amp;nbsp;work.&lt;/p&gt;
&lt;p&gt;Asyncronous programming in Rust is a &lt;a href="https://blog.rust-lang.org/2019/11/07/Async-await-stable.html"&gt;recent addition&lt;/a&gt; to the
language.  If you&amp;#8217;re interested how this feature was designed I recommend
watching &lt;a href="https://www.youtube.com/watch?v=lJ3NC-R3gSI"&gt;Steve Klabnik&amp;#8217;s talk&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Modern languages provide ways of expressing concurrent operations using
built-in language primitives or external libraries.  Writing a simulated search
engine is a great exercise to learn about concurrency because it requires to
think about thread creation, thread cancellation and merging results from
multiple&amp;nbsp;threads.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Deploying thewagner.net</title><link href="https://thewagner.net/blog/2020/07/03/deploying-thewagnernet/" rel="alternate"/><published>2020-07-03T00:00:00+02:00</published><updated>2020-07-03T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2020-07-03:/blog/2020/07/03/deploying-thewagnernet/</id><summary type="html">&lt;p&gt;For a long time I&amp;#8217;ve been manually deploying this blog to &lt;a href="https://pages.github.com/"&gt;GitHub
Pages&lt;/a&gt;.  This worked &lt;span class="caps"&gt;OK&lt;/span&gt; because I publish less than once a month.
But I always wished for a better, automatic solution.  Recently I used Nix to
rebuild &lt;a href="https://thewagner.net/blog/2020/05/31/homelab/"&gt;my home network&lt;/a&gt; and I was curious if I can …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For a long time I&amp;#8217;ve been manually deploying this blog to &lt;a href="https://pages.github.com/"&gt;GitHub
Pages&lt;/a&gt;.  This worked &lt;span class="caps"&gt;OK&lt;/span&gt; because I publish less than once a month.
But I always wished for a better, automatic solution.  Recently I used Nix to
rebuild &lt;a href="https://thewagner.net/blog/2020/05/31/homelab/"&gt;my home network&lt;/a&gt; and I was curious if I can improve the
workflow of publishing my articles to &lt;a href="https://thewagner.net"&gt;thewagner.net&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Ingredients&lt;/h1&gt;
&lt;p&gt;I write the articles in Markdown files which are converted to static &lt;span class="caps"&gt;HTML&lt;/span&gt; files
by &lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt;.  The source content is stored in a &lt;a href="https://github.com/wagdav/thewagner.net"&gt;Git
repository&lt;/a&gt;.  I push to this repository when I write new&amp;nbsp;content.&lt;/p&gt;
&lt;p&gt;The blog is served from &lt;a href="https://pages.github.com/"&gt;GitHub Pages&lt;/a&gt; so I don&amp;#8217;t have to manage
any servers.  GitHub expects the &lt;span class="caps"&gt;HTML&lt;/span&gt; pages in a repository with a specific
name: in my case this is &lt;a href="https://github.com/wagdav/wagdav.github.com"&gt;wagdav.github.com&lt;/a&gt;.  This repository
only hosts generated content. I push to this repository when I want to publish
the changes in the source&amp;nbsp;repository.&lt;/p&gt;
&lt;p&gt;I configured &lt;a href="https://travis-ci.org/"&gt;Travis &lt;span class="caps"&gt;CI&lt;/span&gt;&lt;/a&gt; to execute the build and deploy steps when a change
is committed to the source&amp;nbsp;repository.&lt;/p&gt;
&lt;p&gt;In&amp;nbsp;short:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The source repository &lt;a href="https://github.com/wagdav/thewagner.net"&gt;thewagner.net&lt;/a&gt; stores&amp;nbsp;articles.&lt;/li&gt;
&lt;li&gt;The deployment repository &lt;a href="https://github.com/wagdav/wagdav.github.com"&gt;wagdav.github.io&lt;/a&gt; stores generated
  &lt;span class="caps"&gt;HTML&lt;/span&gt;&amp;nbsp;pages.&lt;/li&gt;
&lt;li&gt;When triggered, Travis &lt;span class="caps"&gt;CI&lt;/span&gt; checks out the source repository, builds the blog
  and pushes the generated files to the deployment&amp;nbsp;repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#8217;s see the build and deploy steps in&amp;nbsp;detail.&lt;/p&gt;
&lt;h1&gt;Build&lt;/h1&gt;
&lt;p&gt;The build pipeline is defined as a &lt;a href="https://github.com/wagdav/thewagner.net/blob/3e423bb/default.nix"&gt;Nix expression&lt;/a&gt;.  I don&amp;#8217;t
explain how it works, but I highlight the steps it&amp;nbsp;performs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build the static website using&amp;nbsp;Pelican.&lt;/li&gt;
&lt;li&gt;Run static analysis on the bash scripts using &lt;a href="https://github.com/koalaman/shellcheck"&gt;shellcheck&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;a href="https://github.com/markdownlint/markdownlint"&gt;markdownlint&lt;/a&gt; to flag formatting issues in the&amp;nbsp;articles.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These steps depend on tools from three different language ecosystems: Pelican
is a Python project, shellcheck and markdownlint are written in Haskell and
Ruby, respectively.  Yet, the &lt;em&gt;only&lt;/em&gt; dependency of running this pipeline is the
Nix package&amp;nbsp;manager.&lt;/p&gt;
&lt;p&gt;To execute all the checks and build the blog I&amp;nbsp;run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nix&lt;span class="w"&gt; &lt;/span&gt;build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All dependencies are pinned to a specific version of Nix Packages therefore
this command always uses the same version of &lt;em&gt;every&lt;/em&gt; tool and library no matter
where or when it is&amp;nbsp;executed.&lt;/p&gt;
&lt;h1&gt;Deploy&lt;/h1&gt;
&lt;p&gt;A &lt;a href="https://github.com/wagdav/thewagner.net/blob/3e423bb/scripts/publish.sh"&gt;shell script&lt;/a&gt; pushes the generated &lt;span class="caps"&gt;HTML&lt;/span&gt; files to the
deployment&amp;nbsp;repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./scripts/publish.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Because the script runs within a Nix shell, again, Nix is the only dependency
and I don&amp;#8217;t have to install any additional tools or libraries to run&amp;nbsp;it.&lt;/p&gt;
&lt;h1&gt;Automate&lt;/h1&gt;
&lt;p&gt;The commands described in the previous sections can be executed on my local
workstation.  However, to deploy my changes reliably I choose &lt;a href="https://travis-ci.org/"&gt;Travis
&lt;span class="caps"&gt;CI&lt;/span&gt;&lt;/a&gt; to automate the build, check and deployment&amp;nbsp;steps.&lt;/p&gt;
&lt;p&gt;The Nix support of Travis &lt;span class="caps"&gt;CI&lt;/span&gt; is fantastic: it takes only &lt;a href="https://github.com/wagdav/thewagner.net/blob/3e423bb/.travis.yml"&gt;seven lines of sweet
&lt;span class="caps"&gt;YAML&lt;/span&gt;&lt;/a&gt; to setup&amp;nbsp;everything:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;nix&lt;/span&gt;

&lt;span class="nt"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;script&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;nix-shell scripts/publish.sh $GITHUB_TOKEN&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Behind the scenes this configuration builds the artifacts described in
&lt;a href="https://github.com/wagdav/thewagner.net/blob/3e423bb/default.nix"&gt;default.nix&lt;/a&gt; and executes the &lt;a href="https://github.com/wagdav/thewagner.net/blob/3e423bb/scripts/publish.sh"&gt;publish.sh&lt;/a&gt; when
the change was triggered on&amp;nbsp;the &lt;code&gt;master&lt;/code&gt; branch.  The secret&amp;nbsp;value
&lt;code&gt;GITHUB_TOKEN&lt;/code&gt; is configured on the Travis &lt;span class="caps"&gt;CI&lt;/span&gt; web&amp;nbsp;interface.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Deploying my blog is now fully automatic:  I only push the contents of the
articles to a repository.  A hosted service builds and deploys the &lt;span class="caps"&gt;HTML&lt;/span&gt; pages.
I can develop, test and execute each step of the pipeline locally and  the
dependency on hosted services is isolated to a few lines of&amp;nbsp;code.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Homelab</title><link href="https://thewagner.net/blog/2020/05/31/homelab/" rel="alternate"/><published>2020-05-31T00:00:00+02:00</published><updated>2020-05-31T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2020-05-31:/blog/2020/05/31/homelab/</id><summary type="html">&lt;p&gt;I own a few computers which I use to experiment with new languages, tools and
technologies.  I was dissatisfied with configuration management of these
machines.  I used to install and configure packages manually and I never
remembered what I&amp;#8217;ve changed.  I tried Ansible but I found it tedious to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I own a few computers which I use to experiment with new languages, tools and
technologies.  I was dissatisfied with configuration management of these
machines.  I used to install and configure packages manually and I never
remembered what I&amp;#8217;ve changed.  I tried Ansible but I found it tedious to
maintain playbooks: it&amp;#8217;s hard to remove all assumptions about the current state
of the system you&amp;#8217;re configuring and making all playbook tasks idempotent is
close to&amp;nbsp;impossible.&lt;/p&gt;
&lt;p&gt;This article documents the current state of my home infrastructure which I
configure primarily using &lt;a href="https://nixos.org"&gt;Nix&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can find all the configuration code on &lt;a href="https://github.com/wagdav/homelab"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Routers&lt;/h1&gt;
&lt;p&gt;The external connectivity is provided by a &lt;span class="caps"&gt;DSL&lt;/span&gt; box of my Internet service
provider (&lt;span class="caps"&gt;ISP&lt;/span&gt;).  I change the default settings of this device as little as
possible because, in my experience, these &lt;span class="caps"&gt;ISP&lt;/span&gt; provided boxes break or get
replaced every other&amp;nbsp;year.&lt;/p&gt;
&lt;p&gt;When I have a problem with the box and I call the &lt;span class="caps"&gt;ISP&lt;/span&gt;&amp;#8217;s support line they
usually ask me to reboot the device.  Then, because the reboot rarely solves
anything, they ask me to perform a factory reset.  When this happens all custom
configuration from the box is gone and I have to start from scratch.  I don&amp;#8217;t
want my home network setup to depend on specific features of the &lt;span class="caps"&gt;ISP&lt;/span&gt;-provided&amp;nbsp;box.&lt;/p&gt;
&lt;p&gt;I have a Linksys &lt;span class="caps"&gt;WRT3200ACM&lt;/span&gt; router connected to the &lt;span class="caps"&gt;ISP&lt;/span&gt;&amp;#8217;s box which also
provides WiFi for the apartment.  The router runs OpenWRT and &lt;a href="https://github.com/wagdav/homelab/blob/30a82d2/router/config"&gt;I use a
script&lt;/a&gt; to modify the default settings: change the timezone,
setup WiFi and &lt;span class="caps"&gt;DNS&lt;/span&gt; aliases, install the Prometheus OpenWRT node&amp;nbsp;exporter.&lt;/p&gt;
&lt;h1&gt;NixOS&amp;nbsp;servers&lt;/h1&gt;
&lt;p&gt;After a few weeks of &lt;a href="https://thewagner.net/blog/2020/04/30/exploring-nix/"&gt;exploration and learning&lt;/a&gt; I installed NixOS on all my
computers at home, which&amp;nbsp;include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Old industrial &lt;span class="caps"&gt;PC&lt;/span&gt;&amp;nbsp;(32-bit)&lt;/li&gt;
&lt;li&gt;Intel &lt;span class="caps"&gt;NUC&lt;/span&gt;&amp;nbsp;(64-bit)&lt;/li&gt;
&lt;li&gt;Raspberry Pi 4 (64-bit &lt;span class="caps"&gt;ARM&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;Thinkpad laptop&amp;nbsp;(64-bit)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When it comes to deploying to physical hardware NixOS feels like the endgame.
Because NixOS is designed from the ground up to be declarative I can store all
the configuration of these machines in a &lt;a href="https://github.com/wagdav/homelab"&gt;Git repository&lt;/a&gt;.  The
deployments are atomic: if I break something I can roll back any change.  I can
create a virtual machine from an arbitrary machine configuration, test it
locally, then deploy it to the real hardware. If I remove a service definition
from the configuration files the services will be removed from the servers as&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;Previously I tried managing servers using Salt and Ansible and I&amp;#8217;m never
looking&amp;nbsp;back.&lt;/p&gt;
&lt;p&gt;Let me demonstrate with an example the level of composability Nix enables.  The
core part of the Nix module that configures &lt;a href="https://prometheus.io"&gt;Prometheus&lt;/a&gt;
on one of my nodes reads like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;services&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;prometheus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;scrapeConfigs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

services&lt;span class="o"&gt;.&lt;/span&gt;consul&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;catalog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;prometheus&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="ss"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9090&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

networking&lt;span class="o"&gt;.&lt;/span&gt;firewall&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;allowedTCPPorts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;9090&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This snippet adjusts three separate&amp;nbsp;components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable and configure&amp;nbsp;Prometheus&lt;/li&gt;
&lt;li&gt;Create an entry in the &lt;a href="https://www.consul.io/"&gt;Consul Service Catalog&lt;/a&gt; for
  service&amp;nbsp;discovery&lt;/li&gt;
&lt;li&gt;Open a port in the&amp;nbsp;firewall&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A typical service often relies on other services, monitoring agents, network
configurations and other tools.  However, these dependencies are hard to
express in traditional configuration management tools.  In NixOS they are
described at the same place using a single, unified&amp;nbsp;syntax.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/wagdav/homelab/blob/30a82d2/modules/prometheus.nix"&gt;complete module&lt;/a&gt; also contains the full Prometheus
configuration,&amp;nbsp;the &lt;code&gt;scrapeConfigs&lt;/code&gt; attribute, which I elided&amp;nbsp;here.&lt;/p&gt;
&lt;h1&gt;Sensors&lt;/h1&gt;
&lt;p&gt;I installed temperature and humidity sensors in two rooms and a few smart
switches.  I use Nix to create &lt;a href="https://github.com/wagdav/homelab/blob/30a82d2/nodemcu/shell.nix"&gt;the development environment&lt;/a&gt;
for flashing &lt;a href="https://tasmota.github.io/docs/"&gt;the firmware&lt;/a&gt; and for provisioning these embedded&amp;nbsp;devices.&lt;/p&gt;
&lt;p&gt;Also, I wrote a small &lt;a href="https://github.com/wagdav/homelab/blob/30a82d2/nodemcu/tasmota.nix"&gt;Nix module&lt;/a&gt; to make the sensor
configuration more expressive.  For example, instead of &lt;a href="https://tasmota.github.io/docs/Templates"&gt;a cryptic &lt;span class="caps"&gt;JSON&lt;/span&gt;
document&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;NAME&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ZJ-ESP-IR-B-v2.3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;GPIO&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;FLAG&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;BASE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;the &lt;span class="caps"&gt;GPIO&lt;/span&gt; ports of a &lt;span class="caps"&gt;LED&lt;/span&gt; controller equipped with an infrared receiver are
assigned like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tasmota&lt;span class="o"&gt;.&lt;/span&gt;template &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;ZJ-ESP-IR-B-v2.3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;gpio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; tasmota&lt;span class="o"&gt;.&lt;/span&gt;component&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;GPIO4&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; IRrecv&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="ss"&gt;GPIO5&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; PWM1&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="ss"&gt;GPIO12&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; PWM3&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="ss"&gt;GPIO13&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; PWM2&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The sensors publish their data over &lt;span class="caps"&gt;MQTT&lt;/span&gt;.  Then, a &lt;a href="https://www.influxdata.com/time-series-platform/telegraf/"&gt;Telegraf&lt;/a&gt; service
exports the &lt;span class="caps"&gt;MQTT&lt;/span&gt; messages for Prometheus.  Finally, the Prometheus time series
are displayed in Grafana dashboards.  There are many moving pieces here, but
the resulting configuration is short and readable: for example the module
setting up &lt;span class="caps"&gt;MQTT&lt;/span&gt;-Prometheus conversion is &lt;a href="https://github.com/wagdav/homelab/blob/30a82d2/modules/mqtt.nix"&gt;only 66 lines long&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Today I run the following services on my home&amp;nbsp;computers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Consul and Consul Template:&lt;/em&gt; Service discovery and dynamic service&amp;nbsp;configuration&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Gitolite:&lt;/em&gt; Host private Git&amp;nbsp;repositories&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Grafana:&lt;/em&gt; Display metrics on&amp;nbsp;dashboards&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Mosquitto &lt;span class="caps"&gt;MQTT&lt;/span&gt; broker:&lt;/em&gt; relay messages from the&amp;nbsp;sensors&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Nginx:&lt;/em&gt; &lt;span class="caps"&gt;HTTP&lt;/span&gt; server and reverse&amp;nbsp;proxy&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Prometheus and its exporters:&lt;/em&gt; Collect&amp;nbsp;metrics&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Telegraf:&lt;/em&gt; Export &lt;span class="caps"&gt;MQTT&lt;/span&gt; sensor data as Prometheus&amp;nbsp;metrics&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the future I&amp;#8217;m planning to configure WireGuard &lt;span class="caps"&gt;VPN&lt;/span&gt; access and experiment
with network booting and periodic, &lt;a href="https://grahamc.com/blog/erase-your-darlings"&gt;automatic reinstalling of
NixOS&lt;/a&gt; on my&amp;nbsp;servers.&lt;/p&gt;
&lt;p&gt;Overall I&amp;#8217;m very pleased with this setup.  NixOS allows &lt;a href="https://www.youtube.com/watch?v=DK_iLg2Ekwk"&gt;fearless
tinkering&lt;/a&gt; in my homelab.  Deploying from a &lt;a href="https://github.com/wagdav/homelab"&gt;Git
repository&lt;/a&gt; is easy and requires minimal maintenance.  I can
reconfigure or even reinstall my whole network within&amp;nbsp;minutes.&lt;/p&gt;
&lt;h1&gt;Acknowledgment&lt;/h1&gt;
&lt;p&gt;I&amp;#8217;m thankful to &lt;a href="https://github.com/aledegano/"&gt;Alessandro Degano&lt;/a&gt; for suggesting me
&lt;a href="https://www.influxdata.com/time-series-platform/telegraf/"&gt;Telegraf&lt;/a&gt; and showing me &lt;a href="https://github.com/aledegano/homelab/tree/9f93ea0b296/kubernetes/telegraf"&gt;how to set it up&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Exploring Nix</title><link href="https://thewagner.net/blog/2020/04/30/exploring-nix/" rel="alternate"/><published>2020-04-30T00:00:00+02:00</published><updated>2020-04-30T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2020-04-30:/blog/2020/04/30/exploring-nix/</id><summary type="html">&lt;p&gt;For the last few weeks I&amp;#8217;ve been exploring &lt;a href="https://nixos.org/"&gt;NixOS&lt;/a&gt; and its
related tools.  This article is an experience report and a collection of
learning material I find&amp;nbsp;useful.&lt;/p&gt;
&lt;p&gt;NixOS is a unique Linux distribution with &lt;a href="https://en.wikipedia.org/wiki/NixOS"&gt;origins&lt;/a&gt; in
&lt;a href="https://edolstra.github.io/pubs/phd-thesis.pdf"&gt;research&lt;/a&gt; conducted at Utrecht University.  NixOS handles
software delivery and configuration in …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For the last few weeks I&amp;#8217;ve been exploring &lt;a href="https://nixos.org/"&gt;NixOS&lt;/a&gt; and its
related tools.  This article is an experience report and a collection of
learning material I find&amp;nbsp;useful.&lt;/p&gt;
&lt;p&gt;NixOS is a unique Linux distribution with &lt;a href="https://en.wikipedia.org/wiki/NixOS"&gt;origins&lt;/a&gt; in
&lt;a href="https://edolstra.github.io/pubs/phd-thesis.pdf"&gt;research&lt;/a&gt; conducted at Utrecht University.  NixOS handles
software delivery and configuration in a different way than any other
distribution I know.  The entire operating system is treated as an immutable
value which  makes deploying and maintaining NixOS-based systems easy and&amp;nbsp;reliable.&lt;/p&gt;
&lt;h1&gt;The&amp;nbsp;language&lt;/h1&gt;
&lt;p&gt;NixOS is configured using the
&lt;a href="https://nixos.org/nix/manual/#ch-expression-language"&gt;Nix expression language&lt;/a&gt;:
a small, purely functional programming language.  Besides the usual data types
(booleans, numbers, strings, lists and sets) Nix has some features which are
uncommon in configuration&amp;nbsp;languages.&lt;/p&gt;
&lt;p&gt;Let blocks bind values to symbols. The bindings appear after the&amp;nbsp;keyword &lt;code&gt;let&lt;/code&gt;
and the symbols can be used after the&amp;nbsp;keyword &lt;code&gt;in&lt;/code&gt;.  For example, the&amp;nbsp;expression:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt;
  &lt;span class="ss"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt;
  x &lt;span class="o"&gt;+&lt;/span&gt; y &lt;span class="o"&gt;+&lt;/span&gt; x
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;evaluates&amp;nbsp;to &lt;code&gt;"aba"&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In Nix, functions are first-class values.  A function which adds one to a
value is defined&amp;nbsp;succinctly:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;n&lt;span class="p"&gt;:&lt;/span&gt; n &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Typically, functions take sets as arguments and return sets as results.  This
expression defines and calls&amp;nbsp;the &lt;code&gt;endpoints&lt;/code&gt; function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt;
  &lt;span class="ss"&gt;endpoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; engine&lt;span class="p"&gt;,&lt;/span&gt; domain &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;http://&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;engine&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;domain&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="ss"&gt;https&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;engine&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;domain&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt;
  endpoints &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;google&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="ss"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which evaluates&amp;nbsp;to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;http://google.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="ss"&gt;https&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https://google.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This last example also shows how symbols in the current scope are interpolated
in strings&amp;nbsp;using &lt;code&gt;${}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These constructs are sufficient to read the examples in this article.  For a
comprehensive overview of the language features see &lt;a href="https://learnxinyminutes.com/docs/nix/"&gt;this tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Derivations&lt;/h1&gt;
&lt;p&gt;A &lt;em&gt;derivation&lt;/em&gt;, a core concept of Nix, is a build recipe: it describes how to
obtain, in other words &lt;em&gt;derive&lt;/em&gt;, a component from its inputs.  Let&amp;#8217;s make this
statement more concrete with an&amp;nbsp;example.&lt;/p&gt;
&lt;p&gt;We will use Nix to put a string into a file using a build action equivalent&amp;nbsp;to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;echo hello from Nix &amp;gt; output.txt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This build runs&amp;nbsp;the &lt;code&gt;echo&lt;/code&gt; shell command to generate a file.  The build
requires no input source files, but a shell to be present.  We could&amp;nbsp;use &lt;code&gt;bash&lt;/code&gt;
but from where do we get its&amp;nbsp;executable?&lt;/p&gt;
&lt;p&gt;Typical build systems assume that certain programs are available in the build
environment.  Nix doesn&amp;#8217;t make such assumptions.  Builds are performed in
isolation: no programs, no environment variables, nor access to the outside
world are available unless explicitly&amp;nbsp;specified.&lt;/p&gt;
&lt;p&gt;In programming we use a function to abstract over an input parameter of a
computation.  Let&amp;#8217;s do the same and write a function which&amp;nbsp;takes &lt;code&gt;bash&lt;/code&gt; as
input and returns the build recipe, a&amp;nbsp;derivation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# hello.nix&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; bash &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="nb"&gt;derivation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;bash&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bin/bash&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-c&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;echo hello from Nix &amp;gt; $out&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="ss"&gt;system&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;currentSystem&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;derivation&lt;/code&gt; is keyword of the Nix language.  It&amp;#8217;s represented as a set with
specific attributes: a name, a program and its arguments to produce some
output, and a specification of the operating system&amp;#8217;s architecture where this
derivation can be&amp;nbsp;built.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;bash&lt;/code&gt; argument is a dependency, it refers to a derivation which must be
built before&amp;nbsp;the &lt;code&gt;hello&lt;/code&gt; derivation.&lt;/p&gt;
&lt;p&gt;To understand better the derivation&amp;#8217;s structure, let&amp;#8217;s assume we&amp;nbsp;have &lt;code&gt;bash&lt;/code&gt;
built and we evaluate&amp;nbsp;the &lt;code&gt;hello&lt;/code&gt; derivation.  Nix stores the resulting
derivation in the following&amp;nbsp;structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;/nix/store/61lcv6k65f42d3v8nww7m7k48h7v9mhy-hello.drv&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;outputs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;out&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/nix/store/qcnf97fclrnqppq3h5ld9smqdb8l2ybk-hello&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;inputSrcs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;inputDrvs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;/nix/store/8ynv2wxv6vaa75sbpmz8rnlbv1bxcfzn-bash-4.4-p23.drv&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;out&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;platform&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;x86_64-linux&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;builder&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/nix/store/9si14qjcz8072c0v42zbkglq08s2cg04-bash-4.4-p23/bin/bash&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;args&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;echo hello from Nix &amp;gt; $out&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;env&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;builder&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/nix/store/9si14qjcz8072c0v42zbkglq08s2cg04-bash-4.4-p23/bin/bash&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;out&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/nix/store/qcnf97fclrnqppq3h5ld9smqdb8l2ybk-hello&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;system&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;x86_64-linux&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this representation we can see how Nix stores the build artifacts&amp;nbsp;under
&lt;code&gt;/nix/store&lt;/code&gt;.  The filenames in the store are cryptographic hashes of the
defining Nix expression suffixed with a readable, user-provided&amp;nbsp;name.&lt;/p&gt;
&lt;p&gt;This data structure is a concrete description how to build&amp;nbsp;the &lt;code&gt;hello&lt;/code&gt;
greeting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Outputs&lt;/em&gt;: the derivation yields one output&amp;nbsp;named &lt;code&gt;out&lt;/code&gt;.  The output will be
  stored under the given&amp;nbsp;path.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;InputSrcs&lt;/em&gt;: the derivation requires no input&amp;nbsp;sources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;InputDrvs&lt;/em&gt;: the derivation depends on the derivation which&amp;nbsp;builds &lt;code&gt;bash&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Platform&lt;/em&gt;: on my &lt;span class="caps"&gt;PC&lt;/span&gt; the&amp;nbsp;expression &lt;code&gt;builtin.currentSystem&lt;/code&gt; evaluates&amp;nbsp;to &lt;code&gt;x86_64_linux&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Builder and args&lt;/em&gt;: the program and its arguments we provided, but now
  referencing concrete artifacts in the&amp;nbsp;store.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Env&lt;/em&gt;: the environment variables available during build.  These are
  originating from the derivation&amp;#8217;s attributes we provided in the Nix
  expression.  We&amp;nbsp;reference &lt;code&gt;$out&lt;/code&gt; in the build&amp;nbsp;script.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Derivations are just data without any knowledge of the Nix language.  When
evaluated, a Nix expression typically produces many, interdependent derivations
which are built in topological order, that is each derivation is built after
their dependent&amp;nbsp;derivations.&lt;/p&gt;
&lt;p&gt;Nix builds a component in two&amp;nbsp;stages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Evaluates the expression and writes resulting derivations in the Nix&amp;nbsp;store.&lt;/li&gt;
&lt;li&gt;Builds the derivation and writes build results in the Nix&amp;nbsp;store.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nix expressions provide a high-level language for developers to define
components, component configuration and component relationships.  Derivations
encode build instructions for a single component for a given configuration in a
well-defined&amp;nbsp;environment.&lt;/p&gt;
&lt;p&gt;Nix expressions can be evaluated on any system where Nix is installed.
Derivations may be copied to other nodes for building: to a build farm, or to
nodes with special&amp;nbsp;hardware.&lt;/p&gt;
&lt;h1&gt;Build the&amp;nbsp;example&lt;/h1&gt;
&lt;p&gt;To build the example in the previous section, save the expression in a file&amp;nbsp;named &lt;code&gt;hello.nix&lt;/code&gt; and&amp;nbsp;run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;nix-build&lt;span class="w"&gt; &lt;/span&gt;hello.nix&lt;span class="w"&gt; &lt;/span&gt;--arg&lt;span class="w"&gt; &lt;/span&gt;bash&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(import &amp;lt;nixpkgs&amp;gt; {}).bash&amp;#39;&lt;/span&gt;
&lt;span class="go"&gt;/nix/store/qcnf97fclrnqppq3h5ld9smqdb8l2ybk-hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;--arg&lt;/code&gt; switch tells Nix to use&amp;nbsp;the &lt;code&gt;bash&lt;/code&gt; package from the &lt;a href="https://nixos.org/nixos/packages.html"&gt;Nix Packages
collection&lt;/a&gt;.  &lt;code&gt;nix-build&lt;/code&gt; prints the path where the build result is
stored.  By&amp;nbsp;default, &lt;code&gt;nix-build&lt;/code&gt; also creates a symbolic link to the build
result in the current working directory so it&amp;#8217;s easy to verify if we find the
string we&amp;nbsp;expect:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;result
&lt;span class="go"&gt;hello from Nix&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To see the internal structure of the derivation, run the&amp;nbsp;command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;nix show-derivation /nix/store/qcnf97fclrnqppq3h5ld9smqdb8l2ybk-hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which outputs data structure as shown in the previous&amp;nbsp;section.&lt;/p&gt;
&lt;h1&gt;Composing an operating&amp;nbsp;system&lt;/h1&gt;
&lt;p&gt;The Nix language provides a clean component description formalism: &lt;a href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/all-packages.nix"&gt;a single
expression&lt;/a&gt; builds 40000 packages on multiple platforms.  To
achieve this scale, higher-level abstractions are built from the Nix language&amp;nbsp;primitives.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://nixos.wiki/wiki/Module"&gt;Modules&lt;/a&gt; are functions which return a set with specific&amp;nbsp;attributes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; config&lt;span class="p"&gt;,&lt;/span&gt; pkgs&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;imports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# paths to other modules&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="ss"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# option declarations&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="ss"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# option definitions&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Modules are useful for configuring complete subsystems such as networking,
printing, graphics and so on.  The top-level NixOS configuration, typically
stored&amp;nbsp;in &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt;, is a module itself which may include
other&amp;nbsp;modules.&lt;/p&gt;
&lt;p&gt;For example, the &lt;a href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/firewall.nix"&gt;firewall module&lt;/a&gt; allows you to specify the
open ports of your&amp;nbsp;system:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;networking&lt;span class="o"&gt;.&lt;/span&gt;firewall&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;allowedTCPPorts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The module keeps the intricacies of generating iptables rules within its
implementation.  Our system configuration remains simple and&amp;nbsp;declarative.&lt;/p&gt;
&lt;h1&gt;Applications&lt;/h1&gt;
&lt;p&gt;The existence of &lt;a href="http://nixos.org"&gt;NixOS&lt;/a&gt; proves that the Nix expression
language is a solid foundation for software packaging and software delivery.
NixOS is not the most popular &lt;a href="https://distrowatch.com/table.php?distribution=nixos"&gt;Linux
distribution&lt;/a&gt; today, but
if you felt the pain of server management using tools like Puppet, Salt or
Ansible, you should definitely give NixOS a&amp;nbsp;try.&lt;/p&gt;
&lt;p&gt;You don&amp;#8217;t have to replace your operating system to try Nix.  You can use Nix
packages on &lt;a href="https://nixos.org/nix/"&gt;Linux and Mac systems&lt;/a&gt; to set up and share
build environments for your projects, regardless of what programming languages
and tools you&amp;#8217;re&amp;nbsp;using.&lt;/p&gt;
&lt;p&gt;The Nix model can also be used to &lt;a href="https://github.com/NixOS/nixops"&gt;deploy
servers&lt;/a&gt; and for &lt;a href="https://github.com/NixOS/hydra"&gt;continuous integration and
delivery&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Learn&amp;nbsp;more&lt;/h1&gt;
&lt;p&gt;This section is a collection of online resources which I find useful to learn
about&amp;nbsp;Nix.&lt;/p&gt;
&lt;p&gt;Learn the Nix&amp;nbsp;language:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learnxinyminutes.com/docs/nix/"&gt;Learn X in Y minutes where&amp;nbsp;X=Nix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nixos.org/nix/manual/#ch-expression-language"&gt;Nix Expression Language section of the Nix&amp;nbsp;Manual&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Learn about modules and&amp;nbsp;overlays:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nixos.wiki/wiki/Module"&gt;Modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nixos.wiki/wiki/Overlays"&gt;Overlays&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Browse Nix packages and NixOS&amp;nbsp;options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nixos.org/nixos/packages.html"&gt;Search NixOS&amp;nbsp;packages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nixos.org/nixos/options.html"&gt;Search NixOS&amp;nbsp;options&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Read about the original&amp;nbsp;research:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://edolstra.github.io/pubs/iscsd-scm11-final.pdf"&gt;Integrating Software Construction and Software Deployment&lt;/a&gt;
   (Nix used to be called&amp;nbsp;Maak)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://edolstra.github.io/pubs/phd-thesis.pdf"&gt;The Purely Functional Software Deployment&amp;nbsp;Model&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, the NixOS Wiki contains &lt;a href="https://nixos.wiki/wiki/Resources"&gt;a list of learning resources&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;After a few weeks of learning I&amp;#8217;m amazed by Nix.  I believe NixOS is the best
operating system to deploy from a declarative configuration.  The expression
language, the Nix store, the evaluation and build strategy were built for
painless software&amp;nbsp;deployments.&lt;/p&gt;
&lt;p&gt;If you value infrastructure as code and immutable deployments you should
definitely spend time on Nix and its core&amp;nbsp;concepts.&lt;/p&gt;
&lt;p&gt;I updated my main laptop and my servers at home to NixOS.  The configuration of
all my machines is &lt;a href="https://github.com/wagdav/homelab"&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Parallel mindset</title><link href="https://thewagner.net/blog/2020/02/29/parallel-mindset/" rel="alternate"/><published>2020-02-29T00:00:00+01:00</published><updated>2020-02-29T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2020-02-29:/blog/2020/02/29/parallel-mindset/</id><summary type="html">&lt;p&gt;Perhaps everything in our mainstream programming languages is at least 50 years
old.  Loops, iterators, pointers and references to mutable memory locations
appeared in Fortran or &lt;span class="caps"&gt;ALGOL&lt;/span&gt; and now they are part of all mainstream
programming&amp;nbsp;languages.&lt;/p&gt;
&lt;p&gt;These constructs were designed for developing sequential programs.  But today
computers have many …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Perhaps everything in our mainstream programming languages is at least 50 years
old.  Loops, iterators, pointers and references to mutable memory locations
appeared in Fortran or &lt;span class="caps"&gt;ALGOL&lt;/span&gt; and now they are part of all mainstream
programming&amp;nbsp;languages.&lt;/p&gt;
&lt;p&gt;These constructs were designed for developing sequential programs.  But today
computers have many cores and processors and we want to do more computations in
parallel.  We bolted some parallel features on our sequential programming
languages, but sequentiality remains built into our mindset and our&amp;nbsp;infrastructure.&lt;/p&gt;
&lt;p&gt;We need to change our&amp;nbsp;mindset.&lt;/p&gt;
&lt;h1&gt;Automate&amp;nbsp;parallelism&lt;/h1&gt;
&lt;p&gt;Many programming languages manage allocations of storage automatically.
Instead of the programmer, the compiler or the run-time system claims and frees
memory.  The implementation of this automatism is language&amp;nbsp;specific:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scope-limited
  &lt;a href="https://en.wikipedia.org/wiki/Automatic_variable"&gt;automatic variables&lt;/a&gt;&amp;nbsp;(C++)&lt;/li&gt;
&lt;li&gt;Tracing garbage collection (Java, Python, Go,&amp;nbsp;Haskell)&lt;/li&gt;
&lt;li&gt;Ownership tracking&amp;nbsp;(Rust)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Would it be possible to make parallelism, that is allocation of code to
processors,&amp;nbsp;automatic?&lt;/p&gt;
&lt;p&gt;With automatic memory management we stopped&amp;nbsp;using &lt;code&gt;malloc&lt;/code&gt; and &lt;code&gt;free&lt;/code&gt;.  To
automate parallelism we need to restrict our programming style and give up
sequential programming language artifacts from the&amp;nbsp;sixties.&lt;/p&gt;
&lt;h1&gt;Accidentally&amp;nbsp;complex&lt;/h1&gt;
&lt;p&gt;Let&amp;#8217;s take the textbook example of&amp;nbsp;computing &lt;span class="math"&gt;\(n!\)&lt;/span&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;                  &lt;span class="c1"&gt;# ①&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;   &lt;span class="c1"&gt;# ②&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;     &lt;span class="c1"&gt;# ③&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code is written today&amp;#8217;s most common programming style: sequential,
imperative, mutable and allowing uncontrolled side effects.  Every line of this
function states what happens during&amp;nbsp;execution:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Assign an initial value&amp;nbsp;to &lt;code&gt;result&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use the value&amp;nbsp;of &lt;code&gt;i&lt;/code&gt; drawn from the specified&amp;nbsp;range.&lt;/li&gt;
&lt;li&gt;Mutate &lt;code&gt;result&lt;/code&gt; with the current value&amp;nbsp;of &lt;code&gt;i&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Many consider this implementation &amp;#8220;readable&amp;#8221; and &amp;#8220;simple&amp;#8221; because we are used
to seeing such programs.  But this code contains many &lt;em&gt;accidental&lt;/em&gt; aspects:&amp;nbsp;the
&lt;code&gt;result&lt;/code&gt; accumulator, the intermediate&amp;nbsp;value &lt;code&gt;i&lt;/code&gt;, and the allusion to
sequential execution.  These are unrelated to the original problem statement.
This is a form of complexity &lt;a href="http://curtclifton.net/papers/MoseleyMarks06a.pdf"&gt;caused by control&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Keeping the&amp;nbsp;essential&lt;/h1&gt;
&lt;p&gt;Let&amp;#8217;s strip off everything but the essential from the previous implementation&amp;nbsp;of &lt;code&gt;factorial&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;functools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;reduce&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;operator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mul&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mul&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This implementation reads almost as a pure specification without any view on
the execution.  This form is more unusual but &lt;em&gt;simpler&lt;/em&gt; than before because all
accidental complexity were&amp;nbsp;removed.&lt;/p&gt;
&lt;p&gt;As programmers, we give up the control of the execution order and we let the
runtime environment choose the most efficient execution strategy.  In case of
Python the execution would be similar, or perhaps identical to that of the
first implementation.  Using this declarative style, however, we could imagine
a programming system where the actual execution strategy would depend on
multiple&amp;nbsp;factors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For&amp;nbsp;small &lt;code&gt;n&lt;/code&gt; execute&amp;nbsp;sequentially.&lt;/li&gt;
&lt;li&gt;For&amp;nbsp;large &lt;code&gt;n&lt;/code&gt; split the range among multiple processors, then merge the&amp;nbsp;results.&lt;/li&gt;
&lt;li&gt;Push some parts of the computation to the &lt;span class="caps"&gt;GPU&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;Send the computation to a massively parallel&amp;nbsp;super-computer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general, operations cannot be parallelized arbitrarily.  To allow for such
flexible runtime behavior we must enrich our programs with hints to the
compiler or to the runtime&amp;nbsp;environment.&lt;/p&gt;
&lt;h1&gt;Algebraic&amp;nbsp;properties&lt;/h1&gt;
&lt;p&gt;If we recognize and communicate our problem&amp;#8217;s algebraic properties to the
compiler or to the run-time, it can exploit alternate representations and&amp;nbsp;implementations.&lt;/p&gt;
&lt;p&gt;Well-known algebraic properties translate to useful&amp;nbsp;hints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Associative&lt;/em&gt;: grouping doesn&amp;#8217;t&amp;nbsp;matter&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Commutative&lt;/em&gt;: order doesn&amp;#8217;t&amp;nbsp;matter&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Idempotent&lt;/em&gt;: duplicates don&amp;#8217;t&amp;nbsp;matter&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Identity&lt;/em&gt;: the current value doesn&amp;#8217;t&amp;nbsp;matter&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Zero&lt;/em&gt;: other values don&amp;#8217;t&amp;nbsp;matter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In &lt;code&gt;factorial&lt;/code&gt; the integer multiplication is associative, therefore performing
the multiplication in groups first, then merging the partial results is a
correct parallel implementation.  It is also commutative, so we can do the
merging in any&amp;nbsp;order.&lt;/p&gt;
&lt;h1&gt;Automatic parallelism in&amp;nbsp;practice&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Optimizing_compiler"&gt;Optimizing compilers&lt;/a&gt; generate efficient, often parallel
code from a sequential, imperative code.  But in general, a program organized
according to linear problem decomposition principles is hard to parallelize.
&lt;a href="https://en.wikipedia.org/wiki/Frances_Allen"&gt;Frances Allen&lt;/a&gt; won the 2006
Turing-award for her work in program optimization and&amp;nbsp;parallelization.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dask.org"&gt;Dask&lt;/a&gt; is a flexible parallel computing library for Python.
&lt;a href="https://docs.dask.org/en/latest/#familiar-user-interface"&gt;Its user interface&lt;/a&gt;
mimics the programming experience of popular data processing libraries. For
example, you write regular &lt;a href="https://numpy.org"&gt;NumPy&lt;/a&gt; array manipulation code
and the Dask scheduler distributes the computations across multiple threads or
among the nodes of a&amp;nbsp;cluster.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/facebook/Haxl"&gt;Facebook&amp;#8217;s Haxl library&lt;/a&gt; can automatically
execute independent data fetching operations concurrently.  Haxl, with the
compiler&amp;#8217;s assistance, recognizes algebraic properties such as applicative
functor and monad to generate efficient concurrent code.  &lt;a href="https://www.youtube.com/watch?v=sT6VJkkhy0o"&gt;Simon Marlow&amp;#8217;s
presentation&lt;/a&gt; is a great
introduction of the ideas behind this&amp;nbsp;tool.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;When we code in imperative style, accidental complexity of control creeps into
our programs.  The programmer, instead of the expressing problem&amp;#8217;s essence, is
burdened with managing loops, states and the details of a sequential-looking
runtime&amp;nbsp;behavior.&lt;/p&gt;
&lt;p&gt;Code written in declarative, functional style with no ties to a specific
execution model may be automatically parallelized by the underlying system.
Algebraic properties constrain which execution strategies are correct and&amp;nbsp;efficient.&lt;/p&gt;
&lt;p&gt;The inspiration to this article came from the talk &amp;#8220;Four Solution to a Trivial
Problem&amp;#8221; of &lt;a href="https://en.wikipedia.org/wiki/Guy_L._Steele_Jr."&gt;Guy Steele&lt;/a&gt;.  I recommend watching &lt;a href="https://www.youtube.com/watch?v=ftcIcn8AmSY"&gt;the whole talk on
YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also recommend reading Bartosz Milewski&amp;#8217;s post on &lt;a href="https://bartoszmilewski.com/2010/05/11/parallel-programming-with-hints/"&gt;Parallel Programming with&amp;nbsp;Hints&lt;/a&gt;&lt;/p&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="misc"/></entry><entry><title>The essence of a CI/CD pipeline</title><link href="https://thewagner.net/blog/2020/01/07/the-essence-of-a-cicd-pipeline/" rel="alternate"/><published>2020-01-07T00:00:00+01:00</published><updated>2020-01-07T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2020-01-07:/blog/2020/01/07/the-essence-of-a-cicd-pipeline/</id><summary type="html">&lt;p&gt;Practitioners of &lt;a href="https://en.wikipedia.org/wiki/Continuous_integration"&gt;continuous integration&lt;/a&gt; often describe the
process of &lt;a href="https://en.wikipedia.org/wiki/Build_automation"&gt;automated software delivery&lt;/a&gt; as a
&lt;em&gt;pipeline&lt;/em&gt;: the source code enters the pipe, it is compiled, tested, packaged
and released product comes out on the other&amp;nbsp;end.&lt;/p&gt;
&lt;p&gt;This methaphor evokes the notions of delivering, modularity and continuity.
Teams of different backgrounds relate …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Practitioners of &lt;a href="https://en.wikipedia.org/wiki/Continuous_integration"&gt;continuous integration&lt;/a&gt; often describe the
process of &lt;a href="https://en.wikipedia.org/wiki/Build_automation"&gt;automated software delivery&lt;/a&gt; as a
&lt;em&gt;pipeline&lt;/em&gt;: the source code enters the pipe, it is compiled, tested, packaged
and released product comes out on the other&amp;nbsp;end.&lt;/p&gt;
&lt;p&gt;This methaphor evokes the notions of delivering, modularity and continuity.
Teams of different backgrounds relate to this image even without understanding
each transformation&amp;nbsp;step.&lt;/p&gt;
&lt;p&gt;But what is a software delivery pipeline?  In this post, instead of a metaphor,
I propose a precise mathematical model of&amp;nbsp;it.&lt;/p&gt;
&lt;h1&gt;Concept&amp;nbsp;zoo&lt;/h1&gt;
&lt;p&gt;I reviewed five popular &lt;span class="caps"&gt;CI&lt;/span&gt;/&lt;span class="caps"&gt;CD&lt;/span&gt; systems where users model their software delivery
process by defining a&amp;nbsp;pipeline:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/get-started/key-pipelines-concepts?view=azure-devops"&gt;Azure&amp;nbsp;Pipelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://circleci.com/docs/2.0/concepts/#section=getting-started"&gt;CircleCI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://concourse-ci.org/docs.html"&gt;Concourse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions/core-concepts-for-github-actions"&gt;GitHub&amp;nbsp;Actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.gocd.org/current/introduction/concepts_in_go.html"&gt;GoCD&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#8217;s see how the relevant user documentation describe the pipeline and its
related&amp;nbsp;concepts.&lt;/p&gt;
&lt;h2&gt;Task, action,&amp;nbsp;step&lt;/h2&gt;
&lt;p&gt;The reviewed systems call the pipeline&amp;#8217;s unit of work task, action or&amp;nbsp;step.&lt;/p&gt;
&lt;p&gt;Azure&amp;nbsp;Pipelines&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A step is the smallest building block of a pipeline.  A step can either be a
script or a&amp;nbsp;task.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CircleCI&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A step is an executable&amp;nbsp;command.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Concourse&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A task is the smallest configurable unit.  A task can be thought of as a
function from inputs to outputs that can either succeed or&amp;nbsp;fail.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitHub&amp;nbsp;Actions&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Individual tasks that you combine as steps to create a job. Actions are the
smallest portable building block of a&amp;nbsp;workflow.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GoCD&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A build task is an action that needs to be performed. Usually, it is a single&amp;nbsp;command.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The names differ but they all describe a similar concept:  the unit of work is
an executable script or&amp;nbsp;command.&lt;/p&gt;
&lt;p&gt;Concourse&amp;#8217;s task definition proposes a precise semantic model: a task is a
function.  We will build on this model&amp;nbsp;later.&lt;/p&gt;
&lt;h2&gt;Job&lt;/h2&gt;
&lt;p&gt;A job is an ensemble of tasks, actions or&amp;nbsp;steps.&lt;/p&gt;
&lt;p&gt;Azure&amp;nbsp;Pipelines&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A job represents an execution boundary of a set of steps.  All of the steps
run together on the same&amp;nbsp;agent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CircleCI&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Jobs are collections of&amp;nbsp;steps.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Concourse&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Jobs are sequences steps to&amp;nbsp;execute.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitHub&amp;nbsp;Actions&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A defined task made up of steps. Each step in a job executes in the same&amp;nbsp;runner.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GoCD&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A job consists of multiple tasks, each of which will be run in&amp;nbsp;order.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At this concept the definitions start to diverge, still there are some common&amp;nbsp;points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Actions, tasks or steps build up&amp;nbsp;jobs.&lt;/li&gt;
&lt;li&gt;A job&amp;#8217;s components usually run&amp;nbsp;sequentially.&lt;/li&gt;
&lt;li&gt;A job&amp;#8217;s components usually run on the same build agent, executor or&amp;nbsp;runner.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The notable exceptions&amp;nbsp;are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In Concourse it&amp;#8217;s possible to run a job&amp;#8217;s steps
 &lt;a href="https://concourse-ci.org/jobs.html#in-parallel-step"&gt;in parallel&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In Concourse and GoCD there are no locality guarantees on where the job&amp;#8217;s
  tasks are&amp;nbsp;run.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These job definitions are &lt;a href="https://en.wikipedia.org/wiki/Operational_semantics"&gt;operational&lt;/a&gt; and not
&lt;a href="https://en.wikipedia.org/wiki/Denotational_semantics"&gt;denotational&lt;/a&gt;:  instead of defining what a job &lt;em&gt;means&lt;/em&gt;
they focus on  how a job is &lt;em&gt;executed&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Stage&lt;/h2&gt;
&lt;p&gt;In some systems jobs can be grouped into a&amp;nbsp;stage.&lt;/p&gt;
&lt;p&gt;Azure&amp;nbsp;Pipelines&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A stage is a logical boundary in the pipeline.  Each stage contains one or
more&amp;nbsp;jobs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GoCD&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A stage consists of multiple jobs, each of which can run independently of the&amp;nbsp;others.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Azure Pipelines runs the stages sequentially by default, but arbitrary ordering
can also be defined between them.  This includes no ordering at all, meaning
that stages can run&amp;nbsp;concurrently.&lt;/p&gt;
&lt;p&gt;CircleCI, Concourse and GitHub Actions don&amp;#8217;t have this&amp;nbsp;concept.&lt;/p&gt;
&lt;h2&gt;Pipeline,&amp;nbsp;workflow&lt;/h2&gt;
&lt;p&gt;We now are ready to define a pipeline, also called&amp;nbsp;workflow.&lt;/p&gt;
&lt;p&gt;Azure&amp;nbsp;Pipelines&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A pipeline defines the continuous integration and deployment process for your
app.  It&amp;#8217;s made up of one or more&amp;nbsp;stages.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CircleCI&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Workflows define a list of jobs and their run&amp;nbsp;order.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Concourse&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pipelines are built around jobs and resources.  They represent a dependency&amp;nbsp;flow.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitHub&amp;nbsp;Actions&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Workflows are made up of one or more jobs and can be scheduled or activated
by an&amp;nbsp;event.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GoCD&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A pipeline consists of multiple stages, each of which will be run in&amp;nbsp;order.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Jobs or stages are grouped into pipelines.  The definitions are again
operational with an emphasis of execution order and&amp;nbsp;dependencies.&lt;/p&gt;
&lt;h1&gt;Pipeline,&amp;nbsp;simplified&lt;/h1&gt;
&lt;p&gt;Now we&amp;#8217;ve seen &lt;em&gt;some&lt;/em&gt; of the concepts of the most popular &lt;span class="caps"&gt;CI&lt;/span&gt;/&lt;span class="caps"&gt;CD&lt;/span&gt; systems.  Some
systems have even more which I didn&amp;#8217;t cover&amp;nbsp;here.&lt;/p&gt;
&lt;p&gt;Do we need all these to model the software deliver&amp;nbsp;process?&lt;/p&gt;
&lt;h2&gt;Task as a&amp;nbsp;function&lt;/h2&gt;
&lt;p&gt;Let&amp;#8217;s revisit Concourse&amp;#8217;s task definition: &lt;em&gt;A task can be thought of as a
function from inputs to outputs that can either succeed or&amp;nbsp;fail.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is a great definition because it specifies what a task &lt;em&gt;means&lt;/em&gt; and not
what it does or &lt;em&gt;how&lt;/em&gt; it does it.  Developers can choose to implement a task as
they deem most fitting but the user can think of it as a function no matter&amp;nbsp;what.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s see some task&amp;nbsp;examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A compilation task takes a source code as input and produces a compiled
  binary as&amp;nbsp;output.&lt;/li&gt;
&lt;li&gt;A test task takes the compiled binary as input and produces a test report as&amp;nbsp;output.&lt;/li&gt;
&lt;li&gt;A release task takes the compiled binary and a test report.  If the test
  report is acceptable (no tests fail, test coverage is &lt;span class="caps"&gt;OK&lt;/span&gt;) it releases the
  binary and returns a link to repository where the software can be&amp;nbsp;downloaded.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I named the unit of work &amp;#8220;task&amp;#8221;.  As we&amp;#8217;ve seen other systems prefer &amp;#8220;step&amp;#8221; or
&amp;#8220;action&amp;#8221;, which would be totally fine as&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s write down formally Concourse&amp;#8217;s task&amp;nbsp;definition.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A Task is a &lt;em&gt;function&lt;/em&gt; with two type&amp;nbsp;parameters &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; representing its
input and output types, respectively.  To express possible failure, the output
is wrapped in&amp;nbsp;Haskell&amp;#8217;s &lt;code&gt;Maybe&lt;/code&gt; type.  In other languages this is&amp;nbsp;called
&lt;code&gt;Option&lt;/code&gt;, &lt;code&gt;optional&lt;/code&gt; or &lt;code&gt;Result&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I wrote down this definition in Haskell&amp;#8217;s syntax but this is not important.
What matters is that our model, the Task&amp;#8217;s meaning, is mathematical&amp;nbsp;function.&lt;/p&gt;
&lt;p&gt;These are the type signatures of the tasks described previously in&amp;nbsp;words:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;--         input type        output type&lt;/span&gt;
&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SourceCode&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;CompiledBinary&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;CompiledBinary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;TestReport&lt;/span&gt;
&lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;CompiledBinary&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;TestReport&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;PackageURL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These are &lt;em&gt;not&lt;/em&gt; the implementation of these tasks but their definition
expressed as Haskell&amp;nbsp;code.&lt;/p&gt;
&lt;h2&gt;Sequential&amp;nbsp;composition&lt;/h2&gt;
&lt;p&gt;Let&amp;#8217;s define a task to tests the incoming pull requests of our&amp;nbsp;project.&lt;/p&gt;
&lt;p&gt;This task takes the pull request&amp;#8217;s source code, builds the binary, runs the
tests and returns the test report.  The test report is for the reviewers to
judge the quality of the proposed&amp;nbsp;change.&lt;/p&gt;
&lt;p&gt;In short, we want sequence the&amp;nbsp;tasks &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;.  If we had an operator
with this type&amp;nbsp;signature:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;inSequence&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- first task&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- second task&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;we could express the pull request validating task&amp;nbsp;as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;validatePullRequests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SourceCode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;TestReport&lt;/span&gt;
&lt;span class="nf"&gt;validatePullRequests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inSequence&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;where&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;validatePullRequests&lt;/code&gt; is&amp;nbsp;a &lt;code&gt;Task&lt;/code&gt; because it&amp;#8217;s a function with the right
  type&amp;nbsp;signature&lt;/li&gt;
&lt;li&gt;The source code is fed to the first&amp;nbsp;task, &lt;code&gt;build&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The resulting type&amp;nbsp;of &lt;code&gt;build&lt;/code&gt; is &lt;code&gt;Maybe CompiledBinary&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;build&lt;/code&gt; fails the result of the whole task is&amp;nbsp;failure&lt;/li&gt;
&lt;li&gt;Otherwise, feed the compiled binary&amp;nbsp;to &lt;code&gt;test&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I haven&amp;#8217;t shown you the definition&amp;nbsp;of &lt;code&gt;inSequence&lt;/code&gt;, but you can verify that in
the&amp;nbsp;expression &lt;code&gt;validatePullRequests&lt;/code&gt; the types match.  You can also see&amp;nbsp;that
&lt;code&gt;inSequence&lt;/code&gt; looks almost like regular function composition except the output
types are wrapped&amp;nbsp;in &lt;code&gt;Maybe&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Parallel&amp;nbsp;composition&lt;/h2&gt;
&lt;p&gt;Let&amp;#8217;s consider now two independent&amp;nbsp;tasks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;unitTests&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SourceCode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;UnitTestReport&lt;/span&gt;
&lt;span class="nf"&gt;integrationTests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SourceCode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IntegrationTestReport&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These two test suites could be run in parallel, because they both only depend
on&amp;nbsp;the &lt;code&gt;SourceCode&lt;/code&gt; value.&lt;/p&gt;
&lt;p&gt;We don&amp;#8217;t want to introduce a new concept, but we want the result of parallel
composition to be&amp;nbsp;a &lt;code&gt;Task&lt;/code&gt; as well.  We&amp;#8217;re after an operator with the following
type&amp;nbsp;signature:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;inParallel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The composite task yields the results of input tasks as a tuple.  If &lt;em&gt;any&lt;/em&gt; of
the two task fails, the result of the composite task is failure (represented by
the&amp;nbsp;value &lt;code&gt;Nothing&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;inParallel&lt;/code&gt; we could write a task to run all&amp;nbsp;tests:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;runAllTests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SourceCode&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UnitTestReport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IntegrationTestReport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;runAllTests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inParallel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unitTests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;integrationTests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;inParallel&lt;/code&gt; operator represents a &amp;#8220;fan-out&amp;#8221; structure in the pipeline
where independent transformation steps are applied on the same&amp;nbsp;input.&lt;/p&gt;
&lt;h1&gt;Semantic&amp;nbsp;model&lt;/h1&gt;
&lt;p&gt;In the previous sections we&amp;#8217;ve defined a denotational model for &lt;span class="caps"&gt;CI&lt;/span&gt;/&lt;span class="caps"&gt;CD&lt;/span&gt; build&amp;nbsp;tasks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which maps the Task concept to its meaning, a mathematical object.  This serves
not only as a mental model, but also it allows us introduce regular and
powerful composition&amp;nbsp;rules.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve shown&amp;nbsp;you &lt;code&gt;inSequence&lt;/code&gt; and &lt;code&gt;inParallel&lt;/code&gt; combinators. For reference,
without explanation, here are their&amp;nbsp;definitions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;inSequence&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="nf"&gt;inSequence&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;
&lt;span class="c1"&gt;-- or equivalently&lt;/span&gt;
&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;

&lt;span class="nf"&gt;inParallel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;inParallel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;liftA2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(,)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These combinators are expressed using the task&amp;#8217;s semantic model without
operational terms or unnecessary limiting&amp;nbsp;assumptions.&lt;/p&gt;
&lt;p&gt;It turns out&amp;nbsp;that &lt;code&gt;inSequence&lt;/code&gt; and &lt;code&gt;inParallel&lt;/code&gt; are not primitive operations.
Tasks and their composition rules can be defined using a more general
vocabulary of &lt;a href="https://www.haskell.org/arrows/"&gt;arrows&lt;/a&gt;.  This suggests that
the semantic model is powerful enough to model any software delivery&amp;nbsp;process.&lt;/p&gt;
&lt;p&gt;Using this model, jobs, stages, workflows and pipelines are&amp;nbsp;just &lt;code&gt;Task&lt;/code&gt;s.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Today&amp;#8217;s popular &lt;span class="caps"&gt;CI&lt;/span&gt;/&lt;span class="caps"&gt;CD&lt;/span&gt; systems are built around the metaphor and not a rigorous
definition of a pipeline.  I&amp;nbsp;propose &lt;code&gt;Maybe&lt;/code&gt;-valued functions as a semantic
model for a build task.  Using well-studied and precisely defined rules, tasks
can be composed to model the software delivery&amp;nbsp;process.&lt;/p&gt;
&lt;p&gt;In a future post I will present &lt;a href="https://github.com/wagdav/kevlar"&gt;an experimental
system&lt;/a&gt; which uses these principles to
express continuous integration and continuous delivery&amp;nbsp;pipelines.&lt;/p&gt;
&lt;h1&gt;Acknowledgment&lt;/h1&gt;
&lt;p&gt;Many thanks to the members of the &lt;a href="https://pix4d.com"&gt;Pix4D&lt;/a&gt; &lt;span class="caps"&gt;CI&lt;/span&gt; team for the
inspirational discussions during coffee&amp;nbsp;breaks.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m grateful to &lt;a href="http://conal.net"&gt;Conal Elliott&lt;/a&gt; for reviewing an early draft
of this article and for providing valuable&amp;nbsp;feedback.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Functions in disguise</title><link href="https://thewagner.net/blog/2019/12/20/functions-in-disguise/" rel="alternate"/><published>2019-12-20T00:00:00+01:00</published><updated>2019-12-20T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2019-12-20:/blog/2019/12/20/functions-in-disguise/</id><summary type="html">&lt;p&gt;I argue that we should use functions to simplify configuration&amp;nbsp;files.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Mainstream programming languages support &lt;a href="https://en.wikipedia.org/wiki/Structured_programming"&gt;structured
programming&lt;/a&gt;.  Functions, subroutines and methods make
code more expressive and reduce&amp;nbsp;repetition.&lt;/p&gt;
&lt;p&gt;Pure functions, constructs that produce values by using only their input
arguments and &lt;em&gt;nothing else&lt;/em&gt;, are of particular&amp;nbsp;importance.&lt;/p&gt;
&lt;p&gt;Pure functions express intent explicitly because, by definition, they don&amp;#8217;t
rely on side effects.  Pure functions are easier to test and reason about than
those which have observable side-effects.  This post is only about pure
functions, so I&amp;#8217;m dropping the &amp;#8220;pure&amp;#8221;&amp;nbsp;qualifier.&lt;/p&gt;
&lt;p&gt;In &lt;a href="https://en.wikipedia.org/wiki/Functional_programming"&gt;functional programming&lt;/a&gt; programs are composed of
expressions and declarations of functions.  In this niche domain the utility of
functions is well studied and understood.  Ideas from purely functional
programming languages percolate into mainstream programming languages, but
functional programming is far from&amp;nbsp;mainstream.&lt;/p&gt;
&lt;p&gt;There is, however, a form of functional programming practiced by every
developer every day.  They write configuration files.  This is the hardest form
of functional programming where &lt;em&gt;functions are not used at all&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;Functional&amp;nbsp;configuration&lt;/h1&gt;
&lt;p&gt;Every non-trivial software requires some configuration.  When a program reads
its configuration it executes a small, often trivial functional program.  Let
me show you what I mean with an&amp;nbsp;example.&lt;/p&gt;
&lt;p&gt;Consider the following, &lt;span class="caps"&gt;INI&lt;/span&gt;-style, configuration&amp;nbsp;file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[staging]&lt;/span&gt;
&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;staging.example.com&lt;/span&gt;

&lt;span class="k"&gt;[production]&lt;/span&gt;
&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;#8217;s say that this is a configuration file of a simple service which is
deployed into a specific environment.  First, we deploy it to staging and, when
all the tests pass,  we promote the application to production.  Naturally, the
service&amp;#8217;s address is different in these two&amp;nbsp;environments.&lt;/p&gt;
&lt;p&gt;This is pretty standard, we see similar configuration blocks everywhere.
Where&amp;#8217;s the functional programming&amp;nbsp;here?&lt;/p&gt;
&lt;p&gt;With the configuration blocks we implicitly created a simple function.  Its
imaginary type signature&amp;nbsp;is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;configuration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Environment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Url&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This reads: the configuration is a function from an environment to a &lt;span class="caps"&gt;URL&lt;/span&gt;.
If we saw such a function signature in an application, we could implement it
like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;example.com&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;production&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;staging.example.com&amp;#39;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For clarity I used Python&amp;#8217;s familiar syntax, but this is not&amp;nbsp;important.&lt;/p&gt;
&lt;p&gt;Conceptually we can think that after the configuration file is parsed, this
function is evaluated.  In practice, we usually don&amp;#8217;t see this function written
out, but it&amp;#8217;s hidden somewhere between the configuration format parser library
and our application&amp;#8217;s&amp;nbsp;initialization.&lt;/p&gt;
&lt;p&gt;What we see is that a function, a universally useful concept in programming, is
&lt;em&gt;not&lt;/em&gt; being used explicitly to define the program&amp;#8217;s&amp;nbsp;configuration.&lt;/p&gt;
&lt;h1&gt;But the configuration is&amp;nbsp;simple&lt;/h1&gt;
&lt;p&gt;Let&amp;#8217;s continue on the previous example and add more configuration&amp;nbsp;parameters:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[staging]&lt;/span&gt;
&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;staging.example.com&lt;/span&gt;
&lt;span class="na"&gt;db_backend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;postres&lt;/span&gt;
&lt;span class="na"&gt;db_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;%(db_backend).db.example.com&lt;/span&gt;

&lt;span class="k"&gt;[production]&lt;/span&gt;
&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;example.com&lt;/span&gt;
&lt;span class="na"&gt;db_backend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;rds&lt;/span&gt;
&lt;span class="na"&gt;db_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;%(db_backend).amazon.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here I made the database backend of our service configurable.  It&amp;#8217;s a contrived
example, but not completely unrealistic: in staging we use our own Postgres
database engine as opposed to production where we wish to store our data in
Amazon&amp;#8217;s database-as-service offering called Relational Database Service (&lt;span class="caps"&gt;RDS&lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;Note that I reused the value&amp;nbsp;of &lt;code&gt;db_backend&lt;/code&gt; in the definition&amp;nbsp;of &lt;code&gt;db_address&lt;/code&gt;
because I wanted to avoid duplication.  You can parse this configuration file
with &lt;a href="https://docs.python.org/3/library/configparser.html"&gt;Python&amp;#8217;s configparser
module&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Configuration formats with sections and custom interpolation rules are very
common.  Still, there are some interesting questions to&amp;nbsp;ask:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is a valid section&amp;nbsp;name?&lt;/li&gt;
&lt;li&gt;What happens if I repeat the same entry in a&amp;nbsp;section?&lt;/li&gt;
&lt;li&gt;What happens if I omit an entry in a&amp;nbsp;section?&lt;/li&gt;
&lt;li&gt;What are the interpolation rules of the percent&amp;nbsp;expressions?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this specific case, we find the answers in the not so short
&lt;a href="https://docs.python.org/3/library/configparser.html"&gt;documentation&lt;/a&gt;,  but the
point is that a concept like &amp;#8216;configuration block&amp;#8217; looks deceptively simple. It
takes quite some effort to precisely explain what a file like this&amp;nbsp;means.&lt;/p&gt;
&lt;p&gt;Now let&amp;#8217;s see how this configuration file looks if we represent it explicitly
as a&amp;nbsp;function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;production&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;example.com&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;db_backend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;postgres&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;db_suffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.db.example.com&amp;#39;&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;staging.example.com&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;db_backend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rds&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;db_suffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.amazon.com&amp;#39;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;db_backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;db_backend&lt;/span&gt;
    &lt;span class="n"&gt;db_address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;db_backend&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;db_suffix&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Is this better than the &lt;span class="caps"&gt;INI&lt;/span&gt; syntax?  Well, not necessarily, but it triggers
different kinds of&amp;nbsp;thoughts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Should we avoid repeating&amp;nbsp;the &lt;code&gt;example.com&lt;/code&gt; domain?&lt;/li&gt;
&lt;li&gt;Should we introduce a richer data type to represent the database&amp;nbsp;configuration?&lt;/li&gt;
&lt;li&gt;Should we split the database configuration in a separate&amp;nbsp;function?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The answers to these questions depend on the specific context.  Note, however,
that these questions are &lt;em&gt;programming&lt;/em&gt; questions.  We raise similar questions
when we write the core of our applications.  Why doesn&amp;#8217;t configuration deserve
the same level of&amp;nbsp;scrutiny?&lt;/p&gt;
&lt;p&gt;Again, I gave the example in Python&amp;#8217;s syntax for simplicity, but the
configuration language doesn&amp;#8217;t have to be Python, but it could support function&amp;nbsp;definitions.&lt;/p&gt;
&lt;h1&gt;Functions hide&amp;nbsp;everywhere&lt;/h1&gt;
&lt;p&gt;Let&amp;#8217;s leave our toy example and look for functions&amp;nbsp;elsewhere.&lt;/p&gt;
&lt;h2&gt;Packer&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.packer.io/"&gt;Packer&lt;/a&gt; is a tool for building machine images.
Its documentation explains how to write configuration
&lt;a href="https://www.packer.io/docs/templates/legacy_json_templates"&gt;templates&lt;/a&gt;
and use
&lt;a href="https://www.packer.io/docs/templates/legacy_json_templates/user-variables"&gt;variables&lt;/a&gt;
to further specialize them from the command&amp;nbsp;line.&lt;/p&gt;
&lt;p&gt;The appearance of the word &amp;#8216;variable&amp;#8217; suggests that some function-related
business may be going on here.  Indeed, Packer templates are functions from
user variables to build instructions.  Interestingly, Packer templates
themselves &lt;a href="https://www.packer.io/docs/templates/hcl_templates/functions"&gt;can call
functions&lt;/a&gt;&amp;nbsp;too.&lt;/p&gt;
&lt;p&gt;Now Packer is a wonderful tool and I&amp;#8217;m not claiming that there&amp;#8217;s anything wrong
with it.  I just want you to realize that in a Packer configuration there lies
an ad hoc, mini functional&amp;nbsp;program.&lt;/p&gt;
&lt;p&gt;Rolling your own implicitly functional configuration language is a lot of
work and it develops some warts.  For example, &lt;a href="https://www.packer.io/docs/templates/legacy_json_templates/user-variables#environment-variables"&gt;there are
restrictions&lt;/a&gt; where you can or cannot use variables in a
Packer template.  Again, this is not a problem, you can use Packer just fine.
It&amp;#8217;s just a pity because variable scoping is pretty well understood since the
development of &lt;span class="caps"&gt;ALGOL&lt;/span&gt; in the&amp;nbsp;1950s.&lt;/p&gt;
&lt;h2&gt;Terraform&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.terraform.io"&gt;Terraform&lt;/a&gt; allows you to define your cloud
infrastructure as code.  I use Terraform every day and I cannot imagine my work
without&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Terraform&amp;#8217;s configuration language already supports &lt;a href="https://www.terraform.io/docs/configuration/functions.html"&gt;various programming
constructs&lt;/a&gt;, but
remains implicitly functional.  You cannot define a function explicitly, but a
&lt;a href="https://www.terraform.io/docs/configuration/modules.html"&gt;&amp;#8220;module&amp;#8221;&lt;/a&gt;.  Just
observe the language used to describe them.  These are quotes from the
documentation, the emphasis is&amp;nbsp;mine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Input variables&lt;/em&gt; to accept values from the calling&amp;nbsp;module.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Output values&lt;/em&gt; to return results to the calling&amp;nbsp;module.&lt;/li&gt;
&lt;li&gt;To &lt;em&gt;call&lt;/em&gt; a module means to include the contents of that module into the
  configuration with specific values for its &lt;em&gt;input variables&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;#8217;s no surprise that modules actually are functions, or they should&amp;nbsp;be.&lt;/p&gt;
&lt;p&gt;You could imagine that when you import a module you compute a value which
contains a bunch of other functions, those that are defined in the module.  In
fact, this is exactly how &lt;a href="https://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript"&gt;JavaScript modules worked&lt;/a&gt; before
the language standard introduced&amp;nbsp;the &lt;code&gt;import&lt;/code&gt; keyword.&lt;/p&gt;
&lt;h2&gt;Ansible and&amp;nbsp;Salt&lt;/h2&gt;
&lt;p&gt;Configuration management systems such as &lt;a href="https://www.ansible.com"&gt;Ansible&lt;/a&gt; and
&lt;a href="https://www.saltstack.com/"&gt;Salt&lt;/a&gt; allow you to manage a large number of
machines.  You specify your servers&amp;#8217; configuration in a &lt;span class="caps"&gt;YAML&lt;/span&gt; file and these
systems make sure that the desired files, software, etc., are deployed on&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;A core feature of these tools is the ability to specify configuration file
templates which are rendered using context specific parameters (for example:
the server&amp;#8217;s assigned &lt;span class="caps"&gt;IP&lt;/span&gt; address).  These templates are functions which take
user parameters as arguments and return the rendered configuration file as a&amp;nbsp;string.&lt;/p&gt;
&lt;p&gt;Salt and Ansible also support structuring your configuration into separate
files.  Sadly they are not called modules, but &lt;a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html"&gt;roles&lt;/a&gt; and
&lt;a href="https://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html"&gt;formulas&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you take a look at the documentation of &lt;a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#role-default-variables"&gt;Ansible roles&lt;/a&gt; you
won&amp;#8217;t be surprised to find word &amp;#8220;variable&amp;#8221; again.  The &lt;a href="https://docs.ansible.com/ansible/latest/index.html"&gt;second
paragraph&lt;/a&gt; of Ansible&amp;#8217;s documentation claims: &lt;em&gt;Ansible&amp;#8217;s main
goals are simplicity and ease of use&lt;/em&gt;.  Take a look how &amp;#8220;simple&amp;#8221; it is to &lt;a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#information-discovered-from-systems-facts"&gt;use
variables&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Warm and fuzzy&amp;nbsp;names&lt;/h1&gt;
&lt;p&gt;What&amp;#8217;s wrong with the names &amp;#8220;template&amp;#8221;, &amp;#8220;role&amp;#8221; and &amp;#8220;formula&amp;#8221;?  Just replace all
their occurrences with the word &amp;#8220;function&amp;#8221; and we&amp;#8217;re done.  Well, no.  It&amp;#8217;s not
at all about&amp;nbsp;linguistics.&lt;/p&gt;
&lt;p&gt;The problem is that your preferred warm and fuzzy name is inevitably more
ambiguous than the concept of a &lt;em&gt;function&lt;/em&gt;.  When you refuse to admit that
you&amp;#8217;re manipulating functions in your software configuration you&amp;#8217;re throwing
away 60+ years worth of computer science.  Additionally, you&amp;#8217;re creating extra
work for yourself to come up with some idiosyncratic rules for your users to
write modular and comprehensible configuration files for your&amp;nbsp;system.&lt;/p&gt;
&lt;p&gt;Why not use functions as the core abstraction to build up configuration files?
Functions can be composed using rigorous, well-defined mathematical rules.  A
functional configuration language could provide few, but powerful concepts to
author configuration files for complex software&amp;nbsp;systems.&lt;/p&gt;
&lt;p&gt;Of course this not to say &lt;em&gt;just use Maths and you&amp;#8217;re done&lt;/em&gt;.  There&amp;#8217;s a lot more
to a good configuration language than that.  Nevertheless, I firmly believe
that it&amp;#8217;s possible to provide developer ergonomics, readability on top of solid
concepts borrowed from Mathematics and Computer&amp;nbsp;Science.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Today, configuration files are written in ad hoc, implicitly functional
programming languages where functions don&amp;#8217;t appear explicitly but disguised.
This leads to the proliferation of ill-defined concepts and idiosyncratic&amp;nbsp;rules.&lt;/p&gt;
&lt;p&gt;This makes extremely valuable tools, like those mentioned in this article and
many others, unnecessarily hard to understand, configure and&amp;nbsp;use.&lt;/p&gt;
&lt;p&gt;It is possible to define a disciplined, functional programming language for
configuration files.  I encourage you to take a look at
&lt;a href="https://dhall-lang.org/"&gt;Dhall&lt;/a&gt;.  Get over its unusual syntax and devote some
time understanding the fundamental role of functions in software configuration
and in programming in&amp;nbsp;general.&lt;/p&gt;
&lt;h1&gt;Acknowledgment&lt;/h1&gt;
&lt;p&gt;I&amp;#8217;m grateful to &lt;a href="https://kmdouglass.github.io"&gt;Kyle M. Douglass&lt;/a&gt; for reviewing
an early draft of this article and for providing valuable&amp;nbsp;feedback.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>O’Reilly Velocity Conference 2019</title><link href="https://thewagner.net/blog/2019/11/08/oreilly-velocity-conference-2019/" rel="alternate"/><published>2019-11-08T00:00:00+01:00</published><updated>2019-11-08T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2019-11-08:/blog/2019/11/08/oreilly-velocity-conference-2019/</id><summary type="html">&lt;p&gt;I spent three days on the O&amp;#8217;Reilly Veocity conference in Berlin.  This post
documents the sessions I liked the&amp;nbsp;most.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Between November 5-7 I spent three days on the &lt;a href="https://conferences.oreilly.com/velocity/vl-eu"&gt;O&amp;#8217;Reilly Velocity&lt;/a&gt; conference.
This post documents the sessions I liked the&amp;nbsp;most.&lt;/p&gt;
&lt;p&gt;The conference organizers collected the speaker slides
&lt;a href="https://conferences.oreilly.com/velocity/vl-eu/public/schedule/proceedings"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Tuesday&lt;/h1&gt;
&lt;p&gt;I travelled to Berlin on Monday and started the conference with two, half-day&amp;nbsp;tutorials.&lt;/p&gt;
&lt;h2&gt;Open Telemetry&amp;nbsp;workshop&lt;/h2&gt;
&lt;p&gt;In this workshop, tutored by Liz Fong-Jones, I learned about OpenTelemetry: a
project aiming to standardize metrics and trace collections from&amp;nbsp;applications.&lt;/p&gt;
&lt;p&gt;Our task was to instrument the provided Go code.  This was an &lt;span class="caps"&gt;HTTP&lt;/span&gt; service
computing the Fibonacci sequence using its recursive definition.  To compute
the preceding two numbers in the sequence the server code repeatedly issues
&lt;span class="caps"&gt;HTTP&lt;/span&gt; client calls to itself.  This implementation is terrible for production,
but it is an excellent classroom&amp;nbsp;example.&lt;/p&gt;
&lt;p&gt;For the practical exercises we wrote the code on &lt;a href="https://glitch.com"&gt;Glitch&lt;/a&gt;.
I think this was a great choice, I could immediately start working on the
execrcises without installing anything on my&amp;nbsp;computer.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opentelemetry.io/docs/"&gt;OpenTelemetry&amp;nbsp;documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://godoc.org/go.opentelemetry.io/otel"&gt;Go&amp;nbsp;documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;span class="caps"&gt;SRE&lt;/span&gt; classroom&amp;nbsp;(PubSub)&lt;/h2&gt;
&lt;p&gt;In this workshop Google engineers lead us to design a strongly consistent,
multi-datacenter queue.  The instructors described how the system should
behave, what latencies are tolerated, what failures modes are allowed.  We
formed groups of five-six people to come-up with an implementation plan.  Then,
we created a bill of materials to estimate the cost of building the&amp;nbsp;system.&lt;/p&gt;
&lt;h1&gt;Wednesday&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;The power of good abstractions in systems design&lt;/em&gt; Lorenzo Saino&amp;nbsp;(Fastly)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lorenzosaino.github.io/talks/keynote-velocityeu19.pdf"&gt;slides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lorenzosaino.github.io"&gt;speaker&amp;#8217;s&amp;nbsp;homepage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;90% of the problems are solved with just 40 basic&amp;nbsp;principles&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/TRIZ"&gt;&lt;span class="caps"&gt;TRIZ&lt;/span&gt; - theory of inventive problem&amp;nbsp;solving&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Kubernetes the very hard way&lt;/em&gt; Laurent Bemaille&amp;nbsp;(Datadog)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.slideshare.net/lbernail/kubernetes-the-very-hard-way-velocity-berlin-2019"&gt;slides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lbernail"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Privilege escalation in build pipelines&lt;/em&gt; Andreas Sieferlinger&amp;nbsp;(Scout24)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://speakerdeck.com/andreassieferlinger/the-deputy-shot-the-sheriff-privilege-escalation-in-build-pipelines"&gt;slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Grafana and metrics without the hype and anti-patterns&lt;/em&gt; (wasn&amp;#8217;t that good
  finally) Björn Rabenstein (Grafana&amp;nbsp;Labs)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cdn.oreillystatic.com/en/assets/1/event/302/What%20remains%20of%20dashboards%20and%20metrics%20without%20the%20hype%20and%20anti-patterns%20Presentation.pdf"&gt;slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Configuration is riskier than code&lt;/em&gt; Jamie Wilkinson&amp;nbsp;(Google)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://conferences.oreilly.com/velocity/vl-eu/public/schedule/detail/78800"&gt;event&amp;nbsp;page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;M3 and Prometheus&lt;/em&gt;  Rob Skillington (Chronosphere), Łukasz Szczęsny&amp;nbsp;(M3)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cdn.oreillystatic.com/en/assets/1/event/302/M3%20and%20Prometheus_%20Monitoring%20at%20planet%20scale%20for%20everyone%20Presentation.pdf"&gt;slides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.m3db.io/"&gt;M3&amp;nbsp;project&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Thursday&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Building high-performing engineering teams&lt;/em&gt; Lena Reinhard&amp;nbsp;(CircleCI)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cdn.oreillystatic.com/en/assets/1/event/302/Building%20high-performing%20engineering%20teams%2C%201%20pixel%20at%20a%20time%20Presentation.pdf"&gt;slides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/radar/building-high-performing-engineering-teams-one-pixel-at-a-time/"&gt;recording&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lenareinhard.com/"&gt;speaker&amp;#8217;s&amp;nbsp;homepage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Controlled chaos: devops and security&lt;/em&gt; Kelly Shortridge&amp;nbsp;(Capsule8)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cdn.oreillystatic.com/en/assets/1/event/302/Controlled%20chaos_%20The%20inevitable%20marriage%20of%20DevOps%20and%20security%20Presentation.pdf"&gt;slides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/radar/controlled-chaos-the-inevitable-marriage-of-devops-and-security"&gt;recording&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &amp;#8220;&lt;span class="caps"&gt;DIE&lt;/span&gt;&amp;#8221; triad: distributed, immutable, and ephemeral&amp;nbsp;infrastructure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Cultivating production excellence&lt;/em&gt; Liz Fong-Jones&amp;nbsp;(Honeycomb)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Keptn: Don&amp;#8217;t let your deliver pipelines become your next legacy code&lt;/em&gt;
(Dynatrace&amp;nbsp;Software)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://keptn.sh/"&gt;Keptn&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Stateful systems in the time of orchestrators&lt;/em&gt; Danielle Lancashire&amp;nbsp;(Hashicorp)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.nomadproject.io/guides/stateful-workloads/stateful-workloads.html"&gt;Stateful workloads in&amp;nbsp;Nomad&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Consensus is for everyone&lt;/em&gt; Tess Rinearson (Tendermint&amp;nbsp;Core)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://conferences.oreilly.com/velocity/vl-eu/public/schedule/detail/78516"&gt;event&amp;nbsp;page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lamport.azurewebsites.net/pubs/pubs.html#lamport-paxos"&gt;Original Paxos&amp;nbsp;paper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Consensus_(computer_science)"&gt;Consensus on&amp;nbsp;Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tendermint.com"&gt;Tendermint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="misc"/><category term="review"/><category term="conference"/></entry><entry><title>Polymorphism and testing</title><link href="https://thewagner.net/blog/2019/10/28/polymorphism-and-testing/" rel="alternate"/><published>2019-10-28T00:00:00+01:00</published><updated>2019-10-28T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2019-10-28:/blog/2019/10/28/polymorphism-and-testing/</id><summary type="html">&lt;p&gt;We can make a function more testable by making it a more generic.
Polymorphism allows us to inject test points into our function. This is
often achieved by mocks and fakes in traditional programming&amp;nbsp;languages.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Recently I &lt;a href="https://github.com/fpco/cache-s3/pull/25/files"&gt;contributed a retry functionality&lt;/a&gt; to the cache-s3 Haskell
project.  After I had shared a draft &lt;span class="caps"&gt;PR&lt;/span&gt; with &lt;a href="https://github.com/lehins"&gt;Alexey
Kuleshevich&lt;/a&gt;, the project&amp;#8217;s maintainer, he suggested
some improvements.  In this post I describe a simplified version of the
resulting upstream pull-request and explain how it&amp;nbsp;works.&lt;/p&gt;
&lt;h1&gt;Retrying in case of&amp;nbsp;failure&lt;/h1&gt;
&lt;p&gt;Retrying is a simple error recovery algorithm.  Communicating software
components regularly experience network failures.  If the network outage is
intermittent, retransmitting the data shortly after a failing transfer may
succeed. Thus, reducing the apparent error rate of the&amp;nbsp;subsystem.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fpcomplete.com/blog/2018/02/cache-ci-builds-to-an-s3-bucket"&gt;cache-s3&lt;/a&gt; is used by continuous integration (&lt;span class="caps"&gt;CI&lt;/span&gt;) systems for storing a
compilation cache database in an S3 bucket.  Typically, a successful build is
followed by the upload of the cache database, so that it can be reused by the
next build.  If the database upload fails the &lt;span class="caps"&gt;CI&lt;/span&gt; system fails the whole build
task.  This is annoying when you waited a long time for your build, but now you
have no build and nor a saved cache database.  You have to start everything&amp;nbsp;again&amp;#8230;&lt;/p&gt;
&lt;p&gt;Instead, if the upload to the bucket is retried a couple of times the
intermittent network problem is completely hidden from the&amp;nbsp;user.&lt;/p&gt;
&lt;h1&gt;Give me an&amp;nbsp;integer&lt;/h1&gt;
&lt;p&gt;In cache-s3 &lt;a href="https://github.com/fpco/cache-s3/pull/25/files"&gt;a complex &lt;span class="caps"&gt;HTTP&lt;/span&gt; request is retried&lt;/a&gt;, in this post I&amp;#8217;m using a
simpler example.  The action we will retry is a question: we ask the user for an&amp;nbsp;integer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;question&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;question&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;putStr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Give me an integer: &amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;readMaybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getLine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function&amp;nbsp;returns &lt;code&gt;Nothing&lt;/code&gt; if the user enters anything but an&amp;nbsp;integer.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;GHCI&amp;gt; question&lt;/span&gt;
&lt;span class="go"&gt;Give me an integer: 5&lt;/span&gt;
&lt;span class="go"&gt;Just 5&lt;/span&gt;

&lt;span class="go"&gt;GHCI&amp;gt; question&lt;/span&gt;
&lt;span class="go"&gt;Give me an integer: FOO&lt;/span&gt;
&lt;span class="go"&gt;Nothing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If this question is a part of a longer quiz we let the user guess again before
we fail the whole program.  We would like to write a&amp;nbsp;function &lt;code&gt;retry&lt;/code&gt; with the
following type&amp;nbsp;signature:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function takes two arguments: the number of times to retry and the action
to run.  It returns a more perseverant action with the retry logic &amp;#8220;baked-in&amp;#8221;.
In other words&amp;nbsp;the &lt;code&gt;retry&lt;/code&gt; alters the action&amp;#8217;s runtime behavior, but it doesn&amp;#8217;t
change its&amp;nbsp;type.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;retry&lt;/code&gt; will operate like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;GHCI&amp;gt; retry 3 question&lt;/span&gt;
&lt;span class="go"&gt;Give me an integer: text&lt;/span&gt;
&lt;span class="go"&gt;Retrying 1/3&lt;/span&gt;
&lt;span class="go"&gt;Give me an integer: 5.5&lt;/span&gt;
&lt;span class="go"&gt;Retrying 2/3&lt;/span&gt;
&lt;span class="go"&gt;Give me an integer: 5&lt;/span&gt;
&lt;span class="go"&gt;Just 5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example, after the second additional attempt the integer&amp;#8217;s was finally&amp;nbsp;received.&lt;/p&gt;
&lt;h1&gt;Implementing&amp;nbsp;retry&lt;/h1&gt;
&lt;p&gt;Here&amp;#8217;s an implementation&amp;nbsp;of &lt;code&gt;retry&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- ^ number of times to retry&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- ^ action to retry&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;                             &lt;/span&gt;&lt;span class="c1"&gt;-- ①&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="c1"&gt;-- ②&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Nothing&lt;/span&gt;&lt;span class="w"&gt;                                             &lt;/span&gt;&lt;span class="c1"&gt;-- ③&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Nothing&lt;/span&gt;&lt;span class="w"&gt;                                  &lt;/span&gt;&lt;span class="c1"&gt;-- ④&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;putStrLn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Retrying &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- ⑤&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;res&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="c1"&gt;-- ⑥&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;-- ⑦&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function uses a recursive inner function,&amp;nbsp;called &lt;code&gt;go&lt;/code&gt; by&amp;nbsp;convention.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The provided action is executed and its result is passed&amp;nbsp;to &lt;code&gt;go&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The action succeeded, just return its&amp;nbsp;result&lt;/li&gt;
&lt;li&gt;The action failed, try&amp;nbsp;again&lt;/li&gt;
&lt;li&gt;If limit is reached we&amp;nbsp;return &lt;code&gt;Nothing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Otherwise inform the user about the retry in&amp;nbsp;progress&lt;/li&gt;
&lt;li&gt;Re-execute the&amp;nbsp;action&lt;/li&gt;
&lt;li&gt;Pass the result to the next iteration&amp;nbsp;of &lt;code&gt;go&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In real code we&amp;#8217;d &lt;a href="https://en.wikipedia.org/wiki/Exponential_backoff"&gt;wait a bit&lt;/a&gt; before step ⑥ , but now I&amp;#8217;m skipping
this.  You can load this function into an interactive session and try how it
works.  You should see an output similar to that in the previous&amp;nbsp;section.&lt;/p&gt;
&lt;p&gt;Notice&amp;nbsp;that &lt;code&gt;retry&lt;/code&gt; is polymorphic in the action&amp;#8217;s return&amp;nbsp;type &lt;code&gt;a&lt;/code&gt;.  In the
function&amp;#8217;s body we don&amp;#8217;t manipulate this value at all,&amp;nbsp;therefore &lt;code&gt;a&lt;/code&gt; can stand
for &lt;em&gt;any&lt;/em&gt;&amp;nbsp;type.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s develop an automatic test for this function and convince ourselves and
our colleagues that this function really does what it&amp;#8217;s supposed to do.  The
bad news is that in its current shape this function is hard to test because
it&amp;#8217;s doing too much &lt;span class="caps"&gt;IO&lt;/span&gt;&amp;nbsp;operations.&lt;/p&gt;
&lt;p&gt;Next, we are going to&amp;nbsp;make &lt;code&gt;retry&lt;/code&gt; more polymorphic and more&amp;nbsp;testable.&lt;/p&gt;
&lt;h1&gt;Make it more&amp;nbsp;polymorphic&lt;/h1&gt;
&lt;p&gt;The problem with the first implementation is the appearance&amp;nbsp;of &lt;code&gt;IO&lt;/code&gt;.  We need
to get rid of that.  Notice that in the function&amp;#8217;s body we don&amp;#8217;t do &lt;em&gt;abitrary&lt;/em&gt;
&lt;span class="caps"&gt;IO&lt;/span&gt; operation but really just&amp;nbsp;calling &lt;code&gt;putStrLn&lt;/code&gt; as a logging function.  The
appearance of the bind&amp;nbsp;(&lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt;) operator tells us that we exploit that &lt;span class="caps"&gt;IO&lt;/span&gt; is a&amp;nbsp;monad.&lt;/p&gt;
&lt;p&gt;Inspired by these two observations we&amp;nbsp;replace &lt;code&gt;IO&lt;/code&gt; with a&amp;nbsp;generic &lt;code&gt;m&lt;/code&gt; type
constructor with two&amp;nbsp;constraints:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Monad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;HasLogFunc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Monad&lt;/code&gt; typeclass is part of the Prelude (&amp;#8220;built-in&amp;#8221;). We define&amp;nbsp;the
&lt;code&gt;HasLogFunc&lt;/code&gt; class&amp;nbsp;ourselves:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;HasLogFunc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;logInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;

&lt;span class="kr"&gt;instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;HasLogFunc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;logInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;putStrLn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first two lines defines&amp;nbsp;the &lt;code&gt;HasLogFunc&lt;/code&gt; as an interface&amp;nbsp;where &lt;code&gt;logInfo&lt;/code&gt;
must be implemented.  The last two lines&amp;nbsp;provide &lt;code&gt;IO&lt;/code&gt; with an instance of this
interface: the implementation&amp;nbsp;of &lt;code&gt;logInfo&lt;/code&gt; is&amp;nbsp;just &lt;code&gt;putStrLn&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With the following modifications we obtain to a more generic form&amp;nbsp;of &lt;code&gt;retry&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Monad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;HasLogFunc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="c1"&gt;-- ①&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;-- ^ number of times to retry&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- ^ action to retry                       -- ②&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- same code as before&lt;/span&gt;

&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;logInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Retrying &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- ③&lt;/span&gt;

&lt;span class="c1"&gt;-- same code as before&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Two constraints restrict&amp;nbsp;what &lt;code&gt;m&lt;/code&gt; can be: it must be a monad and must have a
   log&amp;nbsp;function&lt;/li&gt;
&lt;li&gt;Instead&amp;nbsp;of &lt;code&gt;IO&lt;/code&gt;-only, the function operates on generic actions&amp;nbsp;of &lt;code&gt;m&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;We&amp;nbsp;replace &lt;code&gt;putStrLn&lt;/code&gt; with &lt;code&gt;logInfo&lt;/code&gt; which is available&amp;nbsp;in &lt;code&gt;HasLogFunc&lt;/code&gt; environment&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This version works exactly the same as the first attempt&amp;nbsp;because &lt;code&gt;IO&lt;/code&gt; is a
monad and we took care of&amp;nbsp;its &lt;code&gt;HasLogFunc&lt;/code&gt; instance.&lt;/p&gt;
&lt;h1&gt;More polymorphic, more&amp;nbsp;testable&lt;/h1&gt;
&lt;p&gt;This new version&amp;nbsp;of &lt;code&gt;retry&lt;/code&gt; is more testable because in our test code we are
free to use&amp;nbsp;any &lt;code&gt;m&lt;/code&gt; (given it satisfies the constraints we imposed) to express
our assertions.  To demonstrate this let&amp;#8217;s test if the right sequence of error
messages are displayed to the user.  For example, if we had an action which
always&amp;nbsp;fails:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;alwaysFails&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;FakeAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;alwaysFails&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Nothing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;#8217;d expect retries until the specified number of attempts is&amp;nbsp;exhausted.&lt;/p&gt;
&lt;p&gt;We want our tests to be pure therefore,  instead of&amp;nbsp;using &lt;code&gt;IO&lt;/code&gt;, we implement&amp;nbsp;a
&lt;code&gt;FakeAction&lt;/code&gt; type using the &lt;a href="https://hackage.haskell.org/package/mtl-1.1.0.2/docs/Control-Monad-Writer-Lazy.html"&gt;Writer monad&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;FakeAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Writer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a &lt;em&gt;monad&lt;/em&gt; which aggregates the log messages of&amp;nbsp;type &lt;code&gt;String&lt;/code&gt;.  We
specify&amp;nbsp;what &lt;code&gt;logInfo&lt;/code&gt; means in this&amp;nbsp;context:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;HasLogFunc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;FakeAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;logInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we can express the always failing&amp;nbsp;scenario:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;retry&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;gives up after the specified time&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;runWriter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alwaysFails&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;shouldBe&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Nothing&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Retrying 1/3&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Retrying 2/3&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Retrying 3/3&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;runWriter&lt;/code&gt; returns the result of the provided action, in this&amp;nbsp;case &lt;code&gt;Nothing&lt;/code&gt;,
paired up with the log messages which were produced during the&amp;nbsp;evaluation.
&lt;code&gt;FakeAction&lt;/code&gt; is pure, it doesn&amp;#8217;t do any &lt;span class="caps"&gt;IO&lt;/span&gt;, but it helps us to&amp;nbsp;test &lt;code&gt;retry&lt;/code&gt;&lt;span class="quo"&gt;&amp;#8216;&lt;/span&gt;s&amp;nbsp;behavior.&lt;/p&gt;
&lt;p&gt;This testing strategy can be further extended to cover other types of effects.
In &lt;a href="https://github.com/wagdav/polymorphism-and-testing"&gt;the complete code samples on GitHub&lt;/a&gt; you&amp;#8217;ll see how I implemented
exponential back-off: in&amp;nbsp;production &lt;code&gt;retry&lt;/code&gt; waits some seconds before it
re-executes the action, however the test code is pure, running fast without any&amp;nbsp;side-effects.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;In this post I presented a simplified version of &lt;a href="https://github.com/fpco/cache-s3/pull/25/files"&gt;this pull-request&lt;/a&gt; which
adds a simple retry mechanism to &lt;a href="https://www.fpcomplete.com/blog/2018/02/cache-ci-builds-to-an-s3-bucket"&gt;cache-s3&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I showed that we can make a function more testable by making it a more generic.
Polymorphism allows us to inject test points into our function.  This is often
achieved by mocks and fakes in traditional programming languages.  In Haskell
exploiting polymorphism is particularly elegant because we can code against
powerful, abstract interfaces such as the&amp;nbsp;monad.&lt;/p&gt;
&lt;p&gt;The code is available on &lt;a href="https://github.com/wagdav/polymorphism-and-testing"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Consistent vocabulary in control flow</title><link href="https://thewagner.net/blog/2019/09/25/consistent-vocabulary-in-control-flow/" rel="alternate"/><published>2019-09-25T00:00:00+02:00</published><updated>2019-09-25T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2019-09-25:/blog/2019/09/25/consistent-vocabulary-in-control-flow/</id><summary type="html">&lt;p&gt;Mainstream programming languages provide various constructs for &lt;a href="https://en.wikipedia.org/wiki/Control_flow"&gt;control
flow&lt;/a&gt;: conditionals, loops,
exceptions, etc.  Many of these can be modeled using the general
&lt;a href="https://en.wikipedia.org/wiki/Map_(higher-order_function)#Generalization"&gt;functor&lt;/a&gt;
concept.  In this post I&amp;#8217;m going to show you&amp;nbsp;how.&lt;/p&gt;
&lt;p&gt;In most programming languages defining a function (or a method, subroutine,
procedure, etc.) is simple.  &lt;em&gt;Using …&lt;/em&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Mainstream programming languages provide various constructs for &lt;a href="https://en.wikipedia.org/wiki/Control_flow"&gt;control
flow&lt;/a&gt;: conditionals, loops,
exceptions, etc.  Many of these can be modeled using the general
&lt;a href="https://en.wikipedia.org/wiki/Map_(higher-order_function)#Generalization"&gt;functor&lt;/a&gt;
concept.  In this post I&amp;#8217;m going to show you&amp;nbsp;how.&lt;/p&gt;
&lt;p&gt;In most programming languages defining a function (or a method, subroutine,
procedure, etc.) is simple.  &lt;em&gt;Using&lt;/em&gt; this function in a real program is more
complex: the function&amp;#8217;s arguments may be missing (None, &lt;span class="caps"&gt;NULL&lt;/span&gt;, nil, etc.), the
computation in the function may fail because of an unexpected condition, the
function&amp;#8217;s input argument may be the result of an asynchronous&amp;nbsp;call.&lt;/p&gt;
&lt;p&gt;In a real program a function call appears in a specific context with a
particular control flow.  In a given context specific edge cases appear which
we must handle as&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;In the next sections I show you how a simple function is typically used in
different contexts.  I&amp;#8217;m using examples written in Python and&amp;nbsp;Haskell.&lt;/p&gt;
&lt;h1&gt;Modeling a&amp;nbsp;camera&lt;/h1&gt;
&lt;p&gt;As a working example, let&amp;#8217;s model a camera with a projection from a
three-dimensional world point coordinates to two-dimensional image point&amp;nbsp;coordinates.&lt;/p&gt;
&lt;p&gt;In Haskell the type signature of such a function&amp;nbsp;is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;project&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;WorldPoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ImagePoint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;where I assume that some reasonable definitions&amp;nbsp;of &lt;code&gt;WorldPoint&lt;/code&gt; and
&lt;code&gt;ImagePoint&lt;/code&gt; exist.  That is, given a world&amp;nbsp;point &lt;code&gt;project&lt;/code&gt; returns a point on
the camera&amp;#8217;s image&amp;nbsp;plane.&lt;/p&gt;
&lt;p&gt;In Python the outline of this function would&amp;nbsp;read:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;world_point&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="o"&gt;...&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;image_point&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The concrete implementation&amp;nbsp;of &lt;code&gt;project&lt;/code&gt; is not important.  For the sake of
this article we can assume that all relevant camera parameters are available in
the function&amp;#8217;s&amp;nbsp;body.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s see how we could use&amp;nbsp;the &lt;code&gt;project&lt;/code&gt; function in various&amp;nbsp;contexts.&lt;/p&gt;
&lt;h1&gt;Simplest&amp;nbsp;case&lt;/h1&gt;
&lt;p&gt;We designed our function to be pure, free of side-effects.  Projecting a single
world point is just a matter of&amp;nbsp;calling &lt;code&gt;project&lt;/code&gt;.  It&amp;#8217;s easy both in&amp;nbsp;Python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;world_point&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and&amp;nbsp;Haskell:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;project&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worldPoint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In a real world program, however, the situation is rarely that&amp;nbsp;simple.&lt;/p&gt;
&lt;h1&gt;Missing&amp;nbsp;value&lt;/h1&gt;
&lt;p&gt;Imagine that a preceding computation provides an empty world point to our
program.  We would like to&amp;nbsp;use &lt;code&gt;project&lt;/code&gt; in this context where the world point
may not be&amp;nbsp;present.&lt;/p&gt;
&lt;p&gt;In Python, the missing value could be represented as&amp;nbsp;a &lt;code&gt;None&lt;/code&gt; value.  Let&amp;#8217;s use
a conditional to check for&amp;nbsp;it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;world_point&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;image_point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;world_point&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# use image_point&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# handle the missing value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a common pattern, you find such conditionals in every code&amp;nbsp;base.&lt;/p&gt;
&lt;p&gt;In Haskell we could accept the world point wrapped in&amp;nbsp;a &lt;code&gt;Maybe&lt;/code&gt; type and&amp;nbsp;use
&lt;code&gt;fmap&lt;/code&gt; to compute a projection in case the world point value is&amp;nbsp;present:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maybeImagePoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maybeWorldPoint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;where the type of the input and output values&amp;nbsp;are &lt;code&gt;Maybe WorldPoint&lt;/code&gt; and
&lt;code&gt;Maybe ImagePoint&lt;/code&gt;,&amp;nbsp;respectively.&lt;/p&gt;
&lt;p&gt;This works,&amp;nbsp;because &lt;code&gt;Maybe&lt;/code&gt; is a functor.  This means we can use the&amp;nbsp;function
&lt;code&gt;fmap&lt;/code&gt; to lift our&amp;nbsp;pure &lt;code&gt;project&lt;/code&gt; function to operate on potentially missing&amp;nbsp;values.&lt;/p&gt;
&lt;h1&gt;Handling a&amp;nbsp;scene&lt;/h1&gt;
&lt;p&gt;We rarely work with a single world point, but with a collection of world points
which I call here a &lt;em&gt;scene&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If we wanted to project an entire scene on a camera, in Python we could use a
list comprehension and&amp;nbsp;write:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;image_points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;world_point&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;world_point&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or more succinctly, using the&amp;nbsp;built-in &lt;code&gt;map&lt;/code&gt; function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;image_points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In &lt;a href="https://pythonclock.org/"&gt;Python 3&lt;/a&gt;, &lt;code&gt;map&lt;/code&gt; returns an iterator which we
explicitly convert to a&amp;nbsp;list.&lt;/p&gt;
&lt;p&gt;In Haskell, choosing a simple list representation for Scene, we&amp;nbsp;write:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- type Scene = [WorldPoint]&lt;/span&gt;
&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;imagePoints&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;where the type&amp;nbsp;of &lt;code&gt;imagePoints&lt;/code&gt; is a list of image&amp;nbsp;points.&lt;/p&gt;
&lt;p&gt;This is almost identical to the Python code&amp;nbsp;using &lt;code&gt;map&lt;/code&gt;.  List is a&amp;nbsp;functor,
&lt;code&gt;fmap&lt;/code&gt; on list applies the provided function on each element.  This is&amp;nbsp;exactly
&lt;code&gt;map&lt;/code&gt; as we know it from&amp;nbsp;Python.&lt;/p&gt;
&lt;h1&gt;Input from a data&amp;nbsp;file&lt;/h1&gt;
&lt;p&gt;Let&amp;#8217;s imagine that the world point is stored on disk in a data file.  Before we
can&amp;nbsp;apply &lt;code&gt;project&lt;/code&gt; we need to read and decode the data&amp;nbsp;file.&lt;/p&gt;
&lt;p&gt;In Python, we wrap the file operation in&amp;nbsp;a &lt;code&gt;try-except&lt;/code&gt; block:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="n"&gt;world_point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_data_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;image_point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;world_point&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DecodeError&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="c1"&gt;# handle the error&lt;/span&gt;
   &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is also fairly common pattern:  the exception handler, if we don&amp;#8217;t forget
to write it, allows us to handle the potential&amp;nbsp;errors.&lt;/p&gt;
&lt;p&gt;In Haskell, it&amp;#8217;s again&amp;nbsp;just &lt;code&gt;fmap&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- worldPointOrError :: Either WorldPoint DecodeError&lt;/span&gt;
&lt;span class="c1"&gt;-- imagePointOrError :: Either ImagePoint DecodeError&lt;/span&gt;
&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;imagePointOrError&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worldPointOrError&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here &lt;code&gt;Either WorldPoint&lt;/code&gt; is the functor&amp;nbsp;and &lt;code&gt;fmap&lt;/code&gt; acts as follows: if the
decoding is&amp;nbsp;successful &lt;code&gt;project&lt;/code&gt; is applied on the returned value.  In case of
error&amp;nbsp;the &lt;code&gt;project&lt;/code&gt; function is not used at all&amp;nbsp;and &lt;code&gt;imagePointOrError&lt;/code&gt; will
contain the returned error&amp;nbsp;value.&lt;/p&gt;
&lt;p&gt;Because the potential failure is encoded in the data type we cannot forget
about error handling: that code would just not&amp;nbsp;compile.&lt;/p&gt;
&lt;h1&gt;Asynchronous&amp;nbsp;request&lt;/h1&gt;
&lt;p&gt;Finally let&amp;#8217;s assume that we read the world point from the network.  Network
communication requires a lot of input/output so let&amp;#8217;s do it concurrently with
other tasks of our&amp;nbsp;application.&lt;/p&gt;
&lt;p&gt;In Python, using the &lt;a href="https://docs.python.org/3/library/asyncio.html"&gt;asyncio
library&lt;/a&gt; we can write
concurrent code using the async/await&amp;nbsp;syntax:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;read_from_network&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;                  &lt;span class="c1"&gt;# ①&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# dummy value&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;async_image_point&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;                  &lt;span class="c1"&gt;# ②&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;read_from_network&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;image_point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;async_image_point&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;  &lt;span class="c1"&gt;# ③&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;read_from_network&lt;/code&gt; is a coroutine simulating an asynchronous action
   obtaining the world point.  In a real application this operation would run
   concurrently with other&amp;nbsp;coroutines.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;async_image_point&lt;/code&gt; applies the projection on the value returned&amp;nbsp;by
   &lt;code&gt;read_from_network&lt;/code&gt;.  This is also a coroutine and it completes after the
    network communication has&amp;nbsp;finished.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;asyncio.run&lt;/code&gt; blocks until the provided coroutine delivers its return&amp;nbsp;value.
   &lt;code&gt;image_point&lt;/code&gt; is now a regular image point&amp;nbsp;value.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now let&amp;#8217;s see how something similar works in&amp;nbsp;Haskell:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;readFromNetwork&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;WorldPoint&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;-- ①&lt;/span&gt;
&lt;span class="nf"&gt;readFromNetwork&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;threadDelay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- µs&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;-- dummy value&lt;/span&gt;

&lt;span class="nf"&gt;imagePoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ImagePoint&lt;/span&gt;
&lt;span class="nf"&gt;imagePoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;worldPoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readFromNetwork&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;-- ②&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worldPoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;-- ③&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;readFromNetwork&lt;/code&gt; simulates the network &lt;span class="caps"&gt;IO&lt;/span&gt;: the body of this function can be
   replaced with calls to a real networking library which do not know anything
   about asynchronous&amp;nbsp;operations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Spawn the network operation asynchronously in a separate (lightweight)
   thread.  Note&amp;nbsp;that &lt;code&gt;async&lt;/code&gt; is just a &lt;a href="https://hackage.haskell.org/package/async-2.2.2/docs/Control-Concurrent-Async.html#v:async"&gt;library
   function&lt;/a&gt;,
   not a special&amp;nbsp;keyword.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We&amp;nbsp;use &lt;code&gt;fmap&lt;/code&gt; to lift the transformation into the asynchronous computation,&amp;nbsp;then &lt;code&gt;wait&lt;/code&gt; blocks until the asynchronous action&amp;nbsp;completes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By looking at the type signature&amp;nbsp;of &lt;code&gt;fmap&lt;/code&gt; specialized to this&amp;nbsp;example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;fmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;WorldPoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ImagePoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;WorldPoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ImagePoint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can see&amp;nbsp;that &lt;code&gt;fmap&lt;/code&gt; constructs a new asynchronous action where the provided
function is applied to the result of the provided asynchronous action.  It
reaches under&amp;nbsp;the &lt;code&gt;Async&lt;/code&gt; constructor and transforms the underlying&amp;nbsp;values.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;We looked at how a pure function is used in four different computational
contexts: missing values, collections, potentially failing and asynchronous&amp;nbsp;actions.&lt;/p&gt;
&lt;p&gt;In Python we used different, specialized language constructs to apply&amp;nbsp;our
&lt;code&gt;project&lt;/code&gt; function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Conditional&lt;/em&gt;: to handle the case when the input point may be&amp;nbsp;missing&lt;/li&gt;
&lt;li&gt;&lt;em&gt;List comprehension (or loop)&lt;/em&gt;: when the function is applied on a collection
  of&amp;nbsp;points&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Try-except block&lt;/em&gt;: when the data file decoding may&amp;nbsp;fail&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Special keywords async/await&lt;/em&gt;: when the function operates on results of
  asynchronous&amp;nbsp;computations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Haskell we always&amp;nbsp;used &lt;code&gt;fmap&lt;/code&gt;, because these seemingly different
computations can all be modeled as a functor.  Instead of using special
language keywords we used one &lt;a href="https://www.youtube.com/watch?v=0if71HOyVjY"&gt;organizing principle borrowed from
Mathematics&lt;/a&gt; where the control flow and the edge cases are
precisely&amp;nbsp;defined.&lt;/p&gt;
&lt;p&gt;You can read more about functors on the &lt;a href="https://wiki.haskell.org/Functor"&gt;Haskell
wiki&lt;/a&gt; or elsewhere on the&amp;nbsp;Internet.&lt;/p&gt;
&lt;p&gt;For the topic I took inspiration from the talk &lt;a href="https://www.youtube.com/watch?v=Z0vkQLLUVGw"&gt;The Human Side of Haskell by
Josh Godsiff&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Concurrency without magic</title><link href="https://thewagner.net/blog/2019/07/15/concurrency-without-magic/" rel="alternate"/><published>2019-07-15T00:00:00+02:00</published><updated>2019-07-15T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2019-07-15:/blog/2019/07/15/concurrency-without-magic/</id><summary type="html">&lt;p&gt;I argue that using a library is the best design pattern. The Haskell
ecosystem offers powerful tools for writing concurrent&amp;nbsp;programs.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://thewagner.net/blog/2018/02/26/concurrency-patterns/"&gt;In a previous post&lt;/a&gt; I demonstrated some
of Haskell&amp;#8217;s features to write concurrent programs.  I developed a simulated
search engine which looked like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;search30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;search30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maxDelay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mapConcurrently&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printResults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I argued that this was a fast, concurrent, replicated and robust version of the
previous iterations.  In the following sections I am going to improve this
example, therefore I suggest reading &lt;a href="https://thewagner.net/blog/2018/02/26/concurrency-patterns/"&gt;the related post to understand how we got
here&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;The faster&amp;nbsp;wins&lt;/h1&gt;
&lt;p&gt;In the heart of&amp;nbsp;the &lt;code&gt;search30&lt;/code&gt; function we find this helper&amp;nbsp;function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchKind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="nf"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;race&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fakeSearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- server 1&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fakeSearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- server 2&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;of&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;Left&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Server1: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;Right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Server2: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;fastest&lt;/code&gt; sends the search query to two replicas of the search backend and
keeps the result from the faster responding server.&amp;nbsp;The &lt;code&gt;race&lt;/code&gt; function from
the &lt;a href="http://hackage.haskell.org/package/async-2.2.1/docs/Control-Concurrent-Async.html"&gt;async&lt;/a&gt; library runs two actions concurrently and returns the result
of the faster.  The slower action is&amp;nbsp;terminated.&lt;/p&gt;
&lt;p&gt;In real code you would replace&amp;nbsp;the &lt;code&gt;fakeSearch&lt;/code&gt; function with an appropriate
search &lt;span class="caps"&gt;API&lt;/span&gt; call but the structure of the function would not change&amp;nbsp;significantly.&lt;/p&gt;
&lt;p&gt;For the sake of this post we explicitly prepend the name of the server from
which the result came.  In a real application this would not be displayed to the
user.  However, we could still store some information about the response&amp;#8217;s
origin for further&amp;nbsp;analysis.&lt;/p&gt;
&lt;p&gt;This implementation&amp;nbsp;of &lt;code&gt;fastest&lt;/code&gt; works well, but only in the special case of
two servers.  What if we want to use more replicas?  Let&amp;#8217;s see how we can add
support for any number of back-end&amp;nbsp;servers.&lt;/p&gt;
&lt;h1&gt;More general&amp;nbsp;race&lt;/h1&gt;
&lt;p&gt;Instead of racing two processes, we&amp;nbsp;start &lt;code&gt;N&lt;/code&gt; instances of&amp;nbsp;the &lt;code&gt;fakeSearch&lt;/code&gt;
action concurrently and receive the result of the fastest.  This is a recurring
pattern in concurrent programming: start many computations and signal if &lt;em&gt;any
of them&lt;/em&gt; completed execution.  In many programming languages, for example
&lt;a href="https://docs.python.org/3/library/asyncio-task.html#asyncio.wait"&gt;Python&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.waitany?view=netframework-4.8"&gt;C#&lt;/a&gt;, you find library functions to solve
this problem.  The naming and the implementation slightly changes from one
language to another, but the underlying concept is the&amp;nbsp;same.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;race&lt;/code&gt; function served us well, so let&amp;#8217;s keep digging in the &lt;a href="http://hackage.haskell.org/package/async-2.2.1/docs/Control-Concurrent-Async.html"&gt;async&lt;/a&gt;
library for something that can help us out again.  It doesn&amp;#8217;t take too long to
locate these two&amp;nbsp;functions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;waitAny&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Wait for any of the supplied Asyncs to complete.&lt;/span&gt;

&lt;span class="nf"&gt;waitAnyCancel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Like waitAny, but also cancels the other asynchronous&lt;/span&gt;
&lt;span class="c1"&gt;-- operations as soon as one has completed.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This looks promising: we can&amp;nbsp;use &lt;code&gt;waitAnyCancel&lt;/code&gt; to achieve the same behavior&amp;nbsp;as &lt;code&gt;race&lt;/code&gt; but for a list of asynchronous&amp;nbsp;operations.&lt;/p&gt;
&lt;p&gt;We cannot just&amp;nbsp;replace &lt;code&gt;race&lt;/code&gt; with &lt;code&gt;waitAnyCancel&lt;/code&gt; because the type signatures
of the two functions are different.  For reference, this&amp;nbsp;is &lt;code&gt;race&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;race&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Either&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We need to think a bit more how to&amp;nbsp;fit &lt;code&gt;waitAnyCancel&lt;/code&gt; into &lt;code&gt;fastest&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Building&amp;nbsp;blocks&lt;/h1&gt;
&lt;p&gt;The central type of the async&amp;nbsp;library, &lt;code&gt;Async a&lt;/code&gt;, represents an asynchronous
operation that yields a value of&amp;nbsp;type &lt;code&gt;a&lt;/code&gt;.  Asynchronous operations can be
spawned using&amp;nbsp;the &lt;code&gt;async&lt;/code&gt; function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The type of the&amp;nbsp;expression &lt;code&gt;fakesearch query kind&lt;/code&gt; is &lt;code&gt;IO String&lt;/code&gt;.  Feeding
this&amp;nbsp;to &lt;code&gt;async&lt;/code&gt;, &lt;code&gt;async (fakesearch query kind)&lt;/code&gt;, we get&amp;nbsp;an &lt;code&gt;IO (Async String)&lt;/code&gt;
which launches the search asynchronously in a separate thread.  We could
replicate&amp;nbsp;this &lt;code&gt;N&lt;/code&gt; times and&amp;nbsp;use &lt;code&gt;waitAnyCancel&lt;/code&gt; to select the fastest query.
However, if we went down this path we would be unable to identify which server
replica gave us the fastest answer.  We would only get back the search
result, but not the winner replica&amp;#8217;s&amp;nbsp;identity.&lt;/p&gt;
&lt;p&gt;When we&amp;nbsp;used &lt;code&gt;race&lt;/code&gt; it was easy to identify the faster replica because we used
pattern matching on the&amp;nbsp;returned &lt;code&gt;Either&lt;/code&gt; value.  &lt;code&gt;waitAnyCancel&lt;/code&gt; does not give
us any hint on &lt;em&gt;which&lt;/em&gt; action in the provided list was the&amp;nbsp;fastest.&lt;/p&gt;
&lt;p&gt;Now,&amp;nbsp;because &lt;code&gt;IO a&lt;/code&gt; is a functor, we can&amp;nbsp;use &lt;code&gt;fmap&lt;/code&gt; (usually abbreviated&amp;nbsp;as
&lt;code&gt;&amp;lt;$&amp;gt;&lt;/code&gt;) to apply a function on the result of the search operation.  Let&amp;#8217;s write
a function which prepends the server&amp;#8217;s identity to the search&amp;nbsp;result:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- prepend the server&amp;#39;s identity to the search result&lt;/span&gt;
&lt;span class="nf"&gt;servedBy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Server &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For example, in case of the second server replica the transformed search action
would&amp;nbsp;read: &lt;code&gt;servedBy 2 &amp;lt;$&amp;gt; fakeSearch query kind&lt;/code&gt;.  The type of this
expression is&amp;nbsp;still &lt;code&gt;IO String&lt;/code&gt; but it yields the search result with the server
name&amp;nbsp;prepended.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s go over the series of transformation steps and see how the expressions
and their types were&amp;nbsp;modified:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- the search API&lt;/span&gt;
&lt;span class="nf"&gt;fakesearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearyKind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;

&lt;span class="c1"&gt;-- fill in the arguments to get IO action that yields a string&lt;/span&gt;
&lt;span class="nf"&gt;fakesearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;

&lt;span class="c1"&gt;-- prepend second replica&amp;#39;s identity to the search result&lt;/span&gt;
&lt;span class="nf"&gt;servedBy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fakesearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;

&lt;span class="c1"&gt;-- a function which prepends the provided replica number to the search result&lt;/span&gt;
&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;servedBy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fakesearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;

&lt;span class="c1"&gt;-- same as before but as an asyncronous action&lt;/span&gt;
&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;servedBy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fakesearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the last two lambda-expressions I kept the replica number as a free
parameter, a form we can reuse in the final&amp;nbsp;step.&lt;/p&gt;
&lt;h1&gt;Final&amp;nbsp;implementation&lt;/h1&gt;
&lt;p&gt;Let&amp;#8217;s assemble the&amp;nbsp;new &lt;code&gt;fastest&lt;/code&gt; implementation from the pieces we&amp;nbsp;have:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchKind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="nf"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;forM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;numReplicas&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="c1"&gt;-- ①&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;servedBy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fakeSearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- &amp;lt;$&amp;gt; is `fmap`  -- ②&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;waitAnyCancel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="c1"&gt;-- ③&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt;                                                       &lt;/span&gt;&lt;span class="c1"&gt;-- ④&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;numReplicas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;servedBy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Server &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;①&amp;nbsp;Use &lt;code&gt;forM&lt;/code&gt; to transform a list of integers, the replica identifiers, by
  applying the provided&amp;nbsp;function. &lt;code&gt;requests&lt;/code&gt; has a&amp;nbsp;type &lt;code&gt;[Async String]&lt;/code&gt;,
  exactly&amp;nbsp;what &lt;code&gt;waitAnyCancel&lt;/code&gt; needs.&lt;/p&gt;
&lt;p&gt;② The second argument&amp;nbsp;of &lt;code&gt;forM&lt;/code&gt; is the transformation function which creates
  an asynchronous operation yielding the search result with the replica&amp;#8217;s
  identity&amp;nbsp;prepended.&lt;/p&gt;
&lt;p&gt;③&amp;nbsp;Call &lt;code&gt;waitAnyCancel&lt;/code&gt; and extract the result from the fastest search
  operation (we don&amp;#8217;t use first element of the returned&amp;nbsp;tuple).&lt;/p&gt;
&lt;p&gt;④ Provide result of the current &lt;span class="caps"&gt;IO&lt;/span&gt;&amp;nbsp;operation.&lt;/p&gt;
&lt;p&gt;This implementation, only six lines of code,  works with any number of
replicas.&amp;nbsp;For &lt;code&gt;numReplicas=2&lt;/code&gt; its behavior is identical to that of the old&amp;nbsp;one.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;We replaced the original implementation of&amp;nbsp;the &lt;code&gt;fastest&lt;/code&gt; function, only capable
of supporting two server replicas, into a more general one which works with any
number of&amp;nbsp;replicas.&lt;/p&gt;
&lt;p&gt;The implementation relies on a single library&amp;nbsp;function &lt;code&gt;waitAnyCancel&lt;/code&gt; but we
needed to arrange the asynchronous search operations in a way that is
compatible&amp;nbsp;with &lt;code&gt;waitAnyCancel&lt;/code&gt;&lt;span class="quo"&gt;&amp;#8216;&lt;/span&gt;s type signature.  We used generic combinators
such&amp;nbsp;as &lt;code&gt;fmap&lt;/code&gt; and &lt;code&gt;forM&lt;/code&gt; to achieve this.&amp;nbsp;The &lt;code&gt;search30&lt;/code&gt; requires no
modifications, as the type signature&amp;nbsp;of &lt;code&gt;fastest&lt;/code&gt; didn&amp;#8217;t&amp;nbsp;change.&lt;/p&gt;
&lt;p&gt;We wrote concurrent code with no locks, no mutexes and no &lt;a href="https://talks.golang.org/2012/concurrency.slide#24"&gt;concurrent design
patterns&lt;/a&gt; to remember.  We manipulate asynchronous
computations as values and call library functions.  This is possible because
the &lt;a href="http://hackage.haskell.org/package/async-2.2.1/docs/Control-Concurrent-Async.html"&gt;async library&lt;/a&gt; exposes generic and composable primitives and hides
the complexity of thread management.  Also the language provides powerful
combinators such&amp;nbsp;as &lt;code&gt;fmap&lt;/code&gt; for implementing our&amp;nbsp;programs.&lt;/p&gt;
&lt;p&gt;You can find the examples given here as &lt;a href="https://github.com/wagdav/haskell-concurrency-patterns"&gt;executable code on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The inspiration of this and &lt;a href="https://thewagner.net/blog/2018/02/26/concurrency-patterns/"&gt;the previous post&lt;/a&gt; came from the
Go examples presented in &lt;a href="https://talks.golang.org/2012/concurrency.slide"&gt;Rob Pike&amp;#8217;s Go Concurrency Patterns
talk&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Build systems à la carte</title><link href="https://thewagner.net/blog/2019/06/19/build-systems-a-la-carte/" rel="alternate"/><published>2019-06-19T00:00:00+02:00</published><updated>2019-06-19T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2019-06-19:/blog/2019/06/19/build-systems-a-la-carte/</id><summary type="html">&lt;p&gt;The work &amp;#8220;Build systems à la carte&amp;#8221; from Andrey Mokhov and his co-workers
taught me a lot about how build systems work.  It demonstrates the power of
Haskell as a modeling&amp;nbsp;language.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today I went to the talk &amp;#8220;Build systems à la carte&amp;#8221; of Andrey Mokhov.  He
presented the results of the identically named paper from last year authored by
himself and his co-authors.  The following links point to the paper and its
related&amp;nbsp;resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://doi.org/10.1145/3236774"&gt;paper submitted to &lt;span class="caps"&gt;ICFP&lt;/span&gt;&amp;nbsp;2018&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=BQVT6wiwCxM"&gt;presentation from &lt;span class="caps"&gt;ICFP&lt;/span&gt; 2018&lt;/a&gt; by
  Simon Peyton-Jones&amp;nbsp;(co-author)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/snowleopard/build/releases/download/jfp-submission/jpf-submission.pdf"&gt;extended version of the original&amp;nbsp;paper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/snowleopard/build/releases/download/slides-lausanne/slides-lausanne.pdf"&gt;slides from today&amp;#8217;s
  presentation&lt;/a&gt;
  (the talk was not&amp;nbsp;recorded)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/snowleopard/build"&gt;code examples on&amp;nbsp;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I had known about this paper from last year and I was excited to learn that
Andrey was going to present this work at &lt;span class="caps"&gt;EPFL&lt;/span&gt;, Lausanne.  In the next sections
I summarize what I learned from the paper and the&amp;nbsp;presentation.&lt;/p&gt;
&lt;h1&gt;Build&amp;nbsp;systems&lt;/h1&gt;
&lt;p&gt;The study explores the design space of build systems such as Make, Ninja,
Bazel.  Interestingly, through the lens of this paper, systems like Excel and
Docker can also be seen as build&amp;nbsp;systems.&lt;/p&gt;
&lt;p&gt;Typically we specify our builds as a set of rules: we tell how a given target
is built out of its dependencies.  The build system&amp;#8217;s job is to bring a
specified target up-to-date.  Depending on the application domain a build
system may have some of the following&amp;nbsp;properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Minimality&lt;/em&gt;: don&amp;#8217;t repeat work&amp;nbsp;unnecessarily&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Early cutoff&lt;/em&gt;: stop when nothing&amp;nbsp;changes&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Cloud builds&lt;/em&gt;: save repeating work by sharing build results among all&amp;nbsp;developers&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Dynamic dependencies&lt;/em&gt;: some dependencies are not known in advance, but they
  are discovered as we run the&amp;nbsp;build.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Classification&amp;nbsp;space&lt;/h1&gt;
&lt;p&gt;Two key design choices are typically deeply wired in any build&amp;nbsp;system:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Scheduling&lt;/em&gt;: the order in which tasks are&amp;nbsp;built&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Rebuilding&lt;/em&gt;: whether or not a task is&amp;nbsp;rebuilt&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Today&amp;#8217;s most commonly used build systems can be classified along these two
axes.  Let&amp;#8217;s see these two aspects in&amp;nbsp;detail.&lt;/p&gt;
&lt;h2&gt;Scheduling&amp;nbsp;strategies&lt;/h2&gt;
&lt;p&gt;Build systems use different strategies to execute the build&amp;nbsp;tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Topological&lt;/em&gt;: all the dependencies are known in advance. The tasks are
  executed in topological order. Examples: Make, Ninja,&amp;nbsp;Buck&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Restarting&lt;/em&gt;: if a task has an non-built dependency its build is aborted and
  restarted later when the dependency is available. Examples: Bazel,&amp;nbsp;Excel&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Suspending&lt;/em&gt;: a task is suspended when its build encounters a missing
  dependency. Examples: Shake,&amp;nbsp;Nix&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The chosen scheduling strategy has an effect on the properties of the resulting
build&amp;nbsp;system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A topological scheduler cannot support dynamic dependencies.  A topological
  order can only be established if all the dependencies are known at the
  beginning of a&amp;nbsp;build.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Build system using restarting schedulers are not minimal because some work is
  repeated when restarted.  Note that the cost of duplicate work may often be
  just a fraction of the overall build&amp;nbsp;cost.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A suspending scheduler is theoretically optimal, but it is only better in
  practice than a restarting scheduler if the cost of avoided duplicate work
  outweighs the cost of suspending&amp;nbsp;tasks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Rebuilding&amp;nbsp;strategies&lt;/h2&gt;
&lt;p&gt;We find the following techniques to decide whether or not a task is&amp;nbsp;rebuilt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Dirty bit&lt;/em&gt;: anything that changed since the last build is marked dirty
  (Excel,&amp;nbsp;Make)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Verifying traces&lt;/em&gt;: rebuild a target if the values/hashes of the its
  dependencies changed since the last build (Ninja,&amp;nbsp;Shake)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Constructive traces&lt;/em&gt;: like verifying traces, but also store the resulting
  target value. The stored value can be shared with other users.&amp;nbsp;(Bazel)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Deep constructive traces&lt;/em&gt;: like constructive traces, but only store terminal
  input keys ignoring any intermediate dependencies (Buck,&amp;nbsp;Nix)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Again, picking a given rebuilding strategy has interesting&amp;nbsp;consequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can achieve minimality using dirty&amp;nbsp;bits.&lt;/li&gt;
&lt;li&gt;It&amp;#8217;s possible but hard to support early cutoff with dirty bits.  Make
  approximates early&amp;nbsp;cut-off.&lt;/li&gt;
&lt;li&gt;All traces support dynamic dependencies and&amp;nbsp;minimality&lt;/li&gt;
&lt;li&gt;All traces except for deep traces support the early cutoff&amp;nbsp;optimization&lt;/li&gt;
&lt;li&gt;Constructive traces enable cloud&amp;nbsp;builds&lt;/li&gt;
&lt;li&gt;Deep constructive traces cannot support early&amp;nbsp;cutoff&lt;/li&gt;
&lt;li&gt;Deep constructive traces may generate frankenbuilds if the tasks are not&amp;nbsp;deterministic&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Executable build system&amp;nbsp;models&lt;/h1&gt;
&lt;p&gt;After a detailed classification of build system the authors present executable
Haskell code to model real-world build systems. The concrete implementations
are broken down into two components: &lt;em&gt;Scheduler&lt;/em&gt; and &lt;em&gt;Rebuilder&lt;/em&gt;,  Here are
some models in their final&amp;nbsp;form:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;topological&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modTimeRebuilder&lt;/span&gt;
&lt;span class="nf"&gt;excel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;restarting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dirtyBitRebuilder&lt;/span&gt;
&lt;span class="nf"&gt;shake&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;suspending&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vtRebuilder&lt;/span&gt;
&lt;span class="nf"&gt;bazel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;restartingQ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctRebuilder&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It&amp;#8217;s remarkable that the concepts presented in this work lead such succint
implementations.  The actual executable code can be found &lt;a href="https://github.com/snowleopard/build/blob/03e891238864f30bc5ac1182a1ba37b8b81dcffb/src/Build/System.hs"&gt;in this
repository&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;The work &amp;#8220;Build systems à la carte&amp;#8221; from Andrey Mokhov and his co-workers
taught me a lot about how build systems work.  It demonstrates the power of
Haskell as a modeling language.  I recommend you to read the paper and study
the related resources shown at the beginning of this&amp;nbsp;article.&lt;/p&gt;</content><category term="misc"/><category term="review"/></entry><entry><title>Exploring parser combinators</title><link href="https://thewagner.net/blog/2019/05/03/exploring-parser-combinators/" rel="alternate"/><published>2019-05-03T00:00:00+02:00</published><updated>2019-05-03T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2019-05-03:/blog/2019/05/03/exploring-parser-combinators/</id><summary type="html">&lt;p&gt;This is an experience report of playing with Megaparsec, a parser
combinator library in&amp;nbsp;Haskell.&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is an experience report of playing with Megaparsec, a parser combinator
library in&amp;nbsp;Haskell.&lt;/p&gt;
&lt;h1&gt;Parser&amp;nbsp;combinators&lt;/h1&gt;
&lt;p&gt;The first time I saw a code snippet using the &lt;a href="https://wiki.haskell.org/Parsec"&gt;Parsec&lt;/a&gt; library I was
truly amazed: &lt;a href="http://book.realworldhaskell.org/read/using-parsec.html"&gt;a parser of Comma-Separated Values(&lt;span class="caps"&gt;CSV&lt;/span&gt;)&lt;/a&gt;&amp;nbsp;reads:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;csvFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;endBy&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eol&lt;/span&gt;
&lt;span class="nf"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;sepBy&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;cell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quotedCell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;|&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;many&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;noneOf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;,&lt;/span&gt;&lt;span class="se"&gt;\n\r&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- quotedCell = ... -- the definition is omitted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I had tried writing a &lt;span class="caps"&gt;CSV&lt;/span&gt; parser by hand before: it was about opening a file,
looping over all the lines, splitting the lines on the comma, looping over
those parts and so on.  In&amp;nbsp;the &lt;code&gt;csvFile&lt;/code&gt; example I didn&amp;#8217;t find any of those:  I
can &lt;em&gt;see&lt;/em&gt; that the code describes the &lt;span class="caps"&gt;CSV&lt;/span&gt; file, but where is all the parsing&amp;nbsp;happening?&lt;/p&gt;
&lt;p&gt;In the previous code-block some notations can be unfamiliar, but this is a
great example of declarative code: you specify &lt;em&gt;what&lt;/em&gt;, and not the &lt;em&gt;how&lt;/em&gt;.  In
fact, if you learn a bit the library, the code almost reads as plain&amp;nbsp;English:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;span class="caps"&gt;CSV&lt;/span&gt; file is zero or more occurrences of lines, separated and ended by&amp;nbsp;end-of-line&lt;/li&gt;
&lt;li&gt;A line is zero or more occurrences of cells, separated by&amp;nbsp;comma&lt;/li&gt;
&lt;li&gt;A cell is either a quoted cell or zero or more characters, excluding comma
  and&amp;nbsp;new-line.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using this &lt;a href="https://www.youtube.com/watch?v=8k_SU1t50M8"&gt;domain specific language&lt;/a&gt; results in code that is not only
declarative, but also compositional: complex parsers are built out of simpler
parsers using the provided combinators.  In our example&amp;nbsp;the &lt;code&gt;line&lt;/code&gt;, &lt;code&gt;cell&lt;/code&gt; and&amp;nbsp;the &lt;code&gt;quotedCell&lt;/code&gt; parsers can be developed, tested and maintained&amp;nbsp;separately.&lt;/p&gt;
&lt;p&gt;Developing parsers in this way is called &lt;a href="https://en.wikipedia.org/wiki/Parser_combinator"&gt;combinatory
parsing&lt;/a&gt; and has a &lt;a href="http://www.cs.nott.ac.uk/~pszgmh/monparsing.pdf"&gt;rich literature&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you ever played with the big guns of parsing such as Lex/Yacc or &lt;span class="caps"&gt;ANTLR&lt;/span&gt; you
can appreciate a whole new level of expressiveness.  The parser combinators are
written as a library of the host language. Here, I am interested in Haskell,
but Parsec-like libraries exist for other languages as well.  Contrary to
traditional parser generators, there&amp;#8217;s no need for preprocessing or external
tooling. In Haskell you can even try your parsers in an interactive &lt;span class="caps"&gt;REPL&lt;/span&gt;
session.  These features make it cheap to write ad-hoc parsers in your&amp;nbsp;programs.&lt;/p&gt;
&lt;h1&gt;Haskell&amp;nbsp;libraries&lt;/h1&gt;
&lt;p&gt;Many parser combinator libraries were written in Haskell; I did some research
to decide which one to use.  I narrowed down my options to&amp;nbsp;three:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://hackage.haskell.org/package/parsec"&gt;Parsec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hackage.haskell.org/package/attoparsec"&gt;Attoparsec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hackage.haskell.org/package/megaparsec"&gt;Megaparsec&lt;/a&gt; (fork of&amp;nbsp;Parsec)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I read somewhere that the original Parsec library may not give the best error
messages when a parser fails.  attoparsec is designed to be super-fast, aimed
particularly at dealing efficiently with network protocols and complicated
text/binary file formats.  Megaparsec promises a &lt;em&gt;&amp;#8220;nice balance between speed,
flexibility, and quality of parse errors&amp;#8221;&lt;/em&gt;.  Sounds good to me.  I decided to
give Megaparsec a&amp;nbsp;try.&lt;/p&gt;
&lt;p&gt;Despite their different internals, these libraries expose a similar interface.
Often it is not too difficult to port code from one library to an other.  The
&lt;a href="https://github.com/mrkkrp/megaparsec#comparison-with-other-solutions"&gt;&lt;span class="caps"&gt;README&lt;/span&gt; of megaparsec&lt;/a&gt; contains a more detailed comparison
with other&amp;nbsp;solutions.&lt;/p&gt;
&lt;h1&gt;Using&amp;nbsp;Megaparsec&lt;/h1&gt;
&lt;p&gt;In spite of  Megaparsec&amp;#8217;s detailed documentation and its &lt;a href="https://markkarpov.com/megaparsec/megaparsec.html"&gt;great
tutorial&lt;/a&gt;, initially I had a
hard time finding the relevant documentation for specific combinators.  The
Megaparsec library organizes its functions in multiple&amp;nbsp;modules/packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://hackage.haskell.org/package/parser-combinators"&gt;parser-combinators&lt;/a&gt;: generic combinators such&amp;nbsp;as
  &lt;code&gt;some&lt;/code&gt;, &lt;code&gt;optional&lt;/code&gt; and &lt;code&gt;sepBy&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://hackage.haskell.org/package/megaparsec-7.0.4/docs/Text-Megaparsec.html"&gt;Megaparsec&lt;/a&gt;: running parsers, primitive and derived combinators.
  For&amp;nbsp;example, &lt;code&gt;parse&lt;/code&gt;, &lt;code&gt;oneOf&lt;/code&gt;, &lt;code&gt;noneOf&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://hackage.haskell.org/package/megaparsec-7.0.4/docs/Text-Megaparsec-Char.html"&gt;Megaparsec.Char&lt;/a&gt;: characters and character groups.
  For&amp;nbsp;example, &lt;code&gt;space&lt;/code&gt;, &lt;code&gt;eol&lt;/code&gt;, &lt;code&gt;tab&lt;/code&gt;, &lt;code&gt;alphaNumChar&lt;/code&gt;, &lt;code&gt;digitChar&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://hackage.haskell.org/package/megaparsec-7.0.4/docs/Text-Megaparsec-Char-Lexer.html"&gt;Megaparsec.Lexer&lt;/a&gt;: high level parsers for handling
  comments, indentation and numbers. For&amp;nbsp;example, &lt;code&gt;skipBlockComment&lt;/code&gt;,
  &lt;code&gt;decimal&lt;/code&gt;, &lt;code&gt;signed&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think this structure is sensible, but it takes a bit to understand.
Especially for beginners it is hard to grasp what is a &lt;em&gt;primitive&lt;/em&gt; and
&lt;em&gt;derived&lt;/em&gt; combinator or what is considered as &lt;em&gt;high-level&lt;/em&gt; and &lt;em&gt;low-level&lt;/em&gt;&amp;nbsp;parser.&lt;/p&gt;
&lt;p&gt;Solving a typical parsing problem, such as parsing a &lt;span class="caps"&gt;CSV&lt;/span&gt;-file, requires only a
handful of library functions.  As soon as you have those combinators figured
out the development becomes a breeze.  I felt that Megaparsec lets me almost
directly transcribe data format specifications into&amp;nbsp;code.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Combinatory parsing is a great way of developing parsers.  Parser-like
libraries demonstrate many good aspects of library design.  They are
compositional but beginners may have a hard time initially dealing with
abstract&amp;nbsp;combinators.&lt;/p&gt;
&lt;p&gt;If you want to learn more about this topic I recommend watching &lt;a href="https://www.youtube.com/watch?v=RDalzi7mhdY"&gt;Scott
Wlaschin&amp;#8217;s presentations on parser combinators&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Load balancer</title><link href="https://thewagner.net/blog/2019/01/30/load-balancer/" rel="alternate"/><published>2019-01-30T00:00:00+01:00</published><updated>2019-01-30T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2019-01-30:/blog/2019/01/30/load-balancer/</id><summary type="html">&lt;p&gt;In this post we are going to write a simple load balancer in Haskell.  The
design is based on that presented in Rob Pike&amp;#8217;s &lt;a href="https://www.youtube.com/watch?v=cN_DpYBzKso"&gt;Concurrency Is Not
Parallelism&lt;/a&gt; talk (starting around 22 minutes).  If you are
not familiar with this presentation I highly recommend watching it before
reading on …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this post we are going to write a simple load balancer in Haskell.  The
design is based on that presented in Rob Pike&amp;#8217;s &lt;a href="https://www.youtube.com/watch?v=cN_DpYBzKso"&gt;Concurrency Is Not
Parallelism&lt;/a&gt; talk (starting around 22 minutes).  If you are
not familiar with this presentation I highly recommend watching it before
reading on.  Pike presents an interesting load balancer design and its
implementation to show off Go&amp;#8217;s built-in concurrency primitives.  &lt;a href="https://thewagner.net/blog/2018/02/26/concurrency-patterns/"&gt;Just like
last year&lt;/a&gt;, I am interested how this
example would look in Haskell, a purely functional programming&amp;nbsp;language.&lt;/p&gt;
&lt;p&gt;I am presenting some code fragments of the implementation omitting some
less-important, plumbing details.  You can find the complete executable code
&lt;a href="https://github.com/wagdav/load-balancer"&gt;in this repository&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Design&lt;/h1&gt;
&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/Load_balancing_(computing)"&gt;load balancer&lt;/a&gt;
distributes workload across multiple computing units.  Load balancing aims to
optimize resource use, maximize throughput, minimize response time, and avoid
overload of any single resource.  I will call our &amp;#8220;computing unit&amp;#8221; simply&amp;nbsp;Worker.&lt;/p&gt;
&lt;p&gt;I have reproduced here the &lt;a href="https://talks.golang.org/2012/waza.slide#45"&gt;outline of the
system&lt;/a&gt; we are going to&amp;nbsp;implement:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;                                   To requester  &amp;lt;──┐&lt;/span&gt;
&lt;span class="go"&gt;┌───────────┐                                       │&lt;/span&gt;
&lt;span class="go"&gt;│ Requester │────┐   ┌──────────┐       ┌────────┐  │&lt;/span&gt;
&lt;span class="go"&gt;└───────────┘    │   │          │─────&amp;gt; │ Worker │──┘&lt;/span&gt;
&lt;span class="go"&gt;                 │   │          │       └────────┘&lt;/span&gt;
&lt;span class="go"&gt;┌───────────┐    └─&amp;gt; │          │       ┌────────┐&lt;/span&gt;
&lt;span class="go"&gt;│ Requester │──────&amp;gt; │ Balancer │─────&amp;gt; │ Worker │────┐&lt;/span&gt;
&lt;span class="go"&gt;└───────────┘    ┌─&amp;gt; │          │       └────────┘    │&lt;/span&gt;
&lt;span class="go"&gt;                 │   │          │       ┌────────┐    │&lt;/span&gt;
&lt;span class="go"&gt;┌───────────┐    │   │          │─────&amp;gt; │ Worker │──┐ │&lt;/span&gt;
&lt;span class="go"&gt;│ Requester │────┘   └──────────┘       └────────┘  │ │&lt;/span&gt;
&lt;span class="go"&gt;└───────────┘                                       │ │&lt;/span&gt;
&lt;span class="go"&gt;                                   To requester  &amp;lt;──┘ │&lt;/span&gt;
&lt;span class="go"&gt;                                                 &amp;lt;────┘&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The design comprises three&amp;nbsp;components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Requester&lt;/em&gt;: Sends a unit of work to the system and waits for the&amp;nbsp;result.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Balancer&lt;/em&gt;: Receives requests and distributes them among the available&amp;nbsp;workers.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Worker&lt;/em&gt;: Executes the requested the work and sends back the result to the&amp;nbsp;Requester.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The components communicate through channels.  I shall use unbounded &lt;span class="caps"&gt;FIFO&lt;/span&gt;
channels from the &lt;a href="https://hackage.haskell.org/package/stm-2.5.0.0/docs/Control-Concurrent-STM-TChan.html"&gt;stm library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The interesting part about this design is that the results from the workers do
not cross the Balancer.  The worker directly sends back the result to the&amp;nbsp;requester.&lt;/p&gt;
&lt;h1&gt;Request&lt;/h1&gt;
&lt;p&gt;First, let&amp;#8217;s define the data structure to hold the requests.  This is a type of
a request that, when executed, yields a value of&amp;nbsp;type &lt;code&gt;a&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;TChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Request&lt;/code&gt; holds&amp;nbsp;an &lt;code&gt;IO&lt;/code&gt; action and a result channel:  the action is the
executable task at hand, the result channel transmits the result back to the
requester.  Both the action and the channel are parametrized over the same
type: the result of the task must &amp;#8220;fit&amp;#8221; in the result&amp;nbsp;channel.&lt;/p&gt;
&lt;h1&gt;The task and the&amp;nbsp;Requester&lt;/h1&gt;
&lt;p&gt;Let&amp;#8217;s start imagining how the clients would interact with the load balancer.
We generate some work&amp;nbsp;with &lt;code&gt;randomTask&lt;/code&gt;, a function with the&amp;nbsp;signature:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;randomTask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Neither the load balancer nor the worker have to know about the internals of
this function.  In my&amp;nbsp;implementation &lt;code&gt;randomTask&lt;/code&gt; draws a number from a uniform
distribution, it sleeps that amount of seconds and returns the number as a
result.  In other words: the result&amp;nbsp;of &lt;code&gt;randomTask&lt;/code&gt; is the time it took to
complete&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;requester&lt;/code&gt; function represent the clients who have some work to&amp;nbsp;perform:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;requester&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;TChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- input channel of the load balancer&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;requester&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;balancer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;forever&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- simulating random load&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;delayMs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getStdRandom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;randomR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;threadDelay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delayMs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- send the request&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;resultChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newTChanIO&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;atomically&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;writeTChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;balancer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;randomTask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;resultChan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- wait for the result&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;atomically&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readTChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;resultChan&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function is an infinite loop where each iteration sends a request to the
load balancer after a random delay.  This is a very primitive way to simulate
some load: not realistic, but good enough for now.  The requester creates the
result channel, packages it up along with the task, sends the request, and
waits for the results asynchronously.  The next iteration will not be&amp;nbsp;blocked.&lt;/p&gt;
&lt;p&gt;Note that the interface to the load balancer is a simple &lt;em&gt;value&lt;/em&gt;.&amp;nbsp;The
&lt;code&gt;requester&lt;/code&gt; only drops this value in a channel and waits.  It does not care
about what happens to&amp;nbsp;the &lt;code&gt;Request&lt;/code&gt; on the other end of the&amp;nbsp;channel.&lt;/p&gt;
&lt;h1&gt;Balancer&lt;/h1&gt;
&lt;p&gt;As shown in the design,&amp;nbsp;the &lt;code&gt;Balancer&lt;/code&gt; receives&amp;nbsp;the &lt;code&gt;Request&lt;/code&gt; from a channel
and distributes them among the available&amp;nbsp;workers.&lt;/p&gt;
&lt;p&gt;The Balancer holds a pool of workers and a completion&amp;nbsp;channel:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Balancer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Balancer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Pool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;TChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;-- Pool and Worker will be defined later&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Workers use the completion channel to report to&amp;nbsp;the &lt;code&gt;Balancer&lt;/code&gt; the completion
of a task.&amp;nbsp;The &lt;code&gt;Balancer&lt;/code&gt; uses this information to keep track of the load of
each&amp;nbsp;worker.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;balance&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;TChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- ^ input channel to receive work from&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Balancer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;-- ^ Balancer&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;balance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;requestChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Balancer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doneChannel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;race_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- ❶&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;runWorkers&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;runBalancer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;runWorkers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mapConcurrently&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(`&lt;/span&gt;&lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doneChannel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;snd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;toList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;                             &lt;/span&gt;&lt;span class="c1"&gt;-- ❷&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;runBalancer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt;                                                 &lt;/span&gt;&lt;span class="c1"&gt;-- ❸&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;atomically&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;WorkerDone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readTChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doneChannel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;orElse&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;RequestReceived&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;$&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readTChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;requestChan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;newPool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;of&lt;/span&gt;&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="c1"&gt;-- ❹&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kt"&gt;RequestReceived&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kt"&gt;WorkerDone&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;completed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;runBalancer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newPool&lt;/span&gt;&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="c1"&gt;-- ❺&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As expected, this is the most complex part of the system.  Let&amp;#8217;s walk through
it step by&amp;nbsp;step:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;balance&lt;/code&gt; function runs the workers and the balancer itself
   asynchronously.&amp;nbsp;The &lt;code&gt;race_&lt;/code&gt; combinator is from the &lt;a href="https://hackage.haskell.org/package/async-2.2.1/docs/Control-Concurrent-Async.html#v:race"&gt;async
   package&lt;/a&gt; and I talked about it in a &lt;a href="https://thewagner.net/blog/2018/02/26/concurrency-patterns/"&gt;previous
   post&lt;/a&gt;.  It runs its two arguments
   concurrently and it terminates if any of those two&amp;nbsp;terminate.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;runWorkers&lt;/code&gt; concurrently executes the workers.  The&amp;nbsp;function &lt;code&gt;work ::
   Worker a -&amp;gt; TChan (Worker a) -&amp;gt; IO ()&lt;/code&gt; is part of the Worker &lt;span class="caps"&gt;API&lt;/span&gt; and makes
   the worker process requests in an infinite loop.  I shall present the
   details of&amp;nbsp;the &lt;code&gt;Worker&lt;/code&gt; in the next&amp;nbsp;section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The balancer waits for new messages on the request and completion&amp;nbsp;channels.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Depending on the received&amp;nbsp;message &lt;code&gt;runBalancer&lt;/code&gt; calls&amp;nbsp;either &lt;code&gt;dispatch&lt;/code&gt; or
   &lt;code&gt;completed&lt;/code&gt;.  These two functions implement the load balancing strategy and
   update the state of the worker&amp;nbsp;pool.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;runBalancer&lt;/code&gt; recursively calls itself with the updated worker&amp;nbsp;pool.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;RequestReceived&lt;/code&gt; and&amp;nbsp;the &lt;code&gt;WorkerDone&lt;/code&gt; are data constructors of an internal&amp;nbsp;type &lt;code&gt;ControlMessage&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ControlMessage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;RequestReceived&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;WorkerDone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This type &amp;#8220;tags&amp;#8221; the incoming message so we can differentiate from where it was&amp;nbsp;originated.&lt;/p&gt;
&lt;p&gt;The communication channels of&amp;nbsp;the &lt;code&gt;Balancer&lt;/code&gt; are now wired up; we are ready to
implement the load balancing strategy.  Following the &lt;a href="https://talks.golang.org/2012/waza.slide#45"&gt;the original
design&lt;/a&gt;, I shall implement the worker pool using a
&lt;a href="https://en.wikipedia.org/wiki/Heap_(data_structure)"&gt;heap&lt;/a&gt; from the
&lt;a href="https://hackage.haskell.org/package/heap-1.0.4/docs/Data-Heap.html"&gt;Data.Heap&lt;/a&gt;&amp;nbsp;module.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Pool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;DH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;MinPrioHeap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This heap stores priority-worker&amp;nbsp;pairs &lt;code&gt;(Int, Worker a)&lt;/code&gt;.  The priority
represents the number of tasks assigned to the worker.  Because we are&amp;nbsp;using
&lt;code&gt;MinPrioHeap&lt;/code&gt; the pair with minimal priority, that corresponding to the least
loaded worker, is extracted&amp;nbsp;first.&lt;/p&gt;
&lt;p&gt;The two&amp;nbsp;functions &lt;code&gt;dispatch&lt;/code&gt; and &lt;code&gt;complete&lt;/code&gt;, introduced in the definition&amp;nbsp;of
&lt;code&gt;balance&lt;/code&gt;, manipulate the heap of the worker pool.  The&amp;nbsp;function &lt;code&gt;dispatch&lt;/code&gt;
selects the least loaded worker and schedules the request on&amp;nbsp;it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Pool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Pool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fromJust&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;DH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- ❶&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="w"&gt;                             &lt;/span&gt;&lt;span class="c1"&gt;-- ❷&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;DH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;-- ❸&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The interface of the heap module is unusual, but the code is only three&amp;nbsp;lines:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The function
   &lt;a href="https://hackage.haskell.org/package/heap-1.0.4/docs/Data-Heap.html#v:view"&gt;view&lt;/a&gt;
   extracts the worker with the minimum priority, that is with the lowest number
   of&amp;nbsp;tasks.&lt;/li&gt;
&lt;li&gt;The&amp;nbsp;function &lt;code&gt;schedule :: Worker a -&amp;gt; Request a -&amp;gt; IO ()&lt;/code&gt; is part of the
   Worker &lt;span class="caps"&gt;API&lt;/span&gt; and it sends the given request to the extracted&amp;nbsp;worker.&lt;/li&gt;
&lt;li&gt;The function
   &lt;a href="https://hackage.haskell.org/package/heap-1.0.4/docs/Data-Heap.html#v:insert"&gt;insert&lt;/a&gt;
   puts back the worker into the pool with an increased priority.  The return
   value is the updated&amp;nbsp;pool.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;completed&lt;/code&gt; function is very similar&amp;nbsp;to &lt;code&gt;dispatch&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;completed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Pool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Pool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="nf"&gt;completed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;DH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;snd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;toList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;in&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;DH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pool&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;First, we look up the given worker using
&lt;a href="https://hackage.haskell.org/package/heap-1.0.4/docs/Data-Heap.html#v:partition"&gt;partition&lt;/a&gt;.
Second, we put it back into the heap with a decreased priority&amp;nbsp;value.&lt;/p&gt;
&lt;h1&gt;Worker&lt;/h1&gt;
&lt;p&gt;The last component of the system is the worker itself.  The worker comprises an
identifier, an integer in this case, and a channel from which it can receive&amp;nbsp;requests:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;TChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;deriving&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Eq&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is the worker&amp;#8217;s main&amp;nbsp;function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;TChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;workerId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;requestChan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doneChannel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;forever&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;resultChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;atomically&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readTChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;requestChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- ❶&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="c1"&gt;-- ❷&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;atomically&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;writeTChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;resultChan&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="c1"&gt;-- ❸&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;writeTChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doneChannel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;workerId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;requestChan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;-- ❹&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It is an infinite loop which (1) reads from the request channel, (2) performs
the task, (3) sends the result to the requester, and (4) reports the completion
to the balancer.  We have already seen the implementations of other ends of
these two&amp;nbsp;channels.&lt;/p&gt;
&lt;p&gt;For better encapsulation I provide a short helper function to send a request to
the&amp;nbsp;worker:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Worker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;atomically&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;writeTChan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The&amp;nbsp;function &lt;code&gt;schedule&lt;/code&gt; deconstructs&amp;nbsp;the &lt;code&gt;Worker&lt;/code&gt; and sends the provided
request to its internal channel.  This function&amp;nbsp;allows &lt;code&gt;Worker&lt;/code&gt; to remain
opaque and the request channel is not exposed outside the worker&amp;#8217;s&amp;nbsp;module.&lt;/p&gt;
&lt;h1&gt;Putting it all&amp;nbsp;together&lt;/h1&gt;
&lt;p&gt;In the previous sections we have seen all the components: the requester, the
balancer, and the workers.  We only have to wire everything&amp;nbsp;up:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;chan&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newTChanIO&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;-- create a channel&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;balancer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newBalancer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- create a `Balancer` with 3 workers&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- run the balancer and the requester concurrently&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;race_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;balancer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requester&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you run the &lt;a href="https://github.com/wagdav/load-balancer"&gt;complete code&lt;/a&gt; you will get an output&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;Balancer: fromList [(0,Worker 2),(1,Worker 3),(0,Worker 1)]&lt;/span&gt;
&lt;span class="go"&gt;Balancer: fromList [(0,Worker 1),(1,Worker 2),(1,Worker 3)]&lt;/span&gt;
&lt;span class="go"&gt;Balancer: fromList [(1,Worker 3),(1,Worker 1),(1,Worker 2)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can see that the first three requests were scheduled on different workers.
The program continues indefinitely and you should see roughly the same amount
of task on each&amp;nbsp;worker.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I presented the Haskell implementation of an interesting load balancer design
based on the &lt;a href="https://talks.golang.org/2012/waza.slide#45"&gt;Go code by Rob Pike&lt;/a&gt;.  The load balancer gives the
incoming request to the least-loaded worker.  The components are loosely
coupled and they communicate via&amp;nbsp;channels.&lt;/p&gt;
&lt;p&gt;Can we deploy this to production?  Certainly not.  The design &lt;em&gt;seems&lt;/em&gt; to scale
up to multiple workers and high request rates, but how can we prove this?  What
kinds of tests could we write for such a concurrent system?  Can we test that
the balancing strategy is sound?  I will try to find answers to these questions
in a future&amp;nbsp;post.&lt;/p&gt;
&lt;p&gt;The full code can be found &lt;a href="https://github.com/wagdav/load-balancer"&gt;in this repository&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Think paper</title><link href="https://thewagner.net/blog/2019/01/03/think-paper/" rel="alternate"/><published>2019-01-03T00:00:00+01:00</published><updated>2019-01-03T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2019-01-03:/blog/2019/01/03/think-paper/</id><summary type="html">&lt;p&gt;Thinking using a computer is hard.  First, a computer is full of distractions,
but let&amp;#8217;s say we can &lt;a href="https://thewagner.net/blog/2016/07/20/working-habits/"&gt;eliminate those&lt;/a&gt;.
Second, using the conventional input such as mouse and a keyboard, anything
more complex than a character or a mouse click is difficult to communicate to
the computer.  Where …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Thinking using a computer is hard.  First, a computer is full of distractions,
but let&amp;#8217;s say we can &lt;a href="https://thewagner.net/blog/2016/07/20/working-habits/"&gt;eliminate those&lt;/a&gt;.
Second, using the conventional input such as mouse and a keyboard, anything
more complex than a character or a mouse click is difficult to communicate to
the computer.  Where&amp;#8217;s the button for my latest vague idea? Or where should I
click to record an abstract&amp;nbsp;concept?&lt;/p&gt;
&lt;p&gt;As an experiment, let&amp;#8217;s say you&amp;#8217;re learning Math.  Try recording digitally
Pythagoras&amp;#8217;s famous formula using the device you&amp;#8217;re reading this post&amp;nbsp;at:&lt;/p&gt;
&lt;div class="math"&gt;$$
a^2 + b^2 = c^2
$$&lt;/div&gt;
&lt;p&gt;Was it easy?  In case you haven&amp;#8217;t reached for your sleek tablet, opened your
cloud-based note taking app which applies instant handwriting recognition and
provides search functionality on &lt;a href="https://www.wolframalpha.com/input/?i=pythagorean+theorem"&gt;Wolfram
Alpha&lt;/a&gt; you may
continue reading.  But let&amp;#8217;s say you type in the equation somehow.  How do you
attach a visual representation to the theorem?  Maybe you can even jot down a
simple proof?  Can you represent your thought process as you&amp;#8217;re working through
all&amp;nbsp;this?&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=yJDv-zdhzMY"&gt;Since at least 1968&lt;/a&gt; human-machine interface designers want to
increase the value created by an intellectual worker provided with a screen, a
keyboard and a mouse.  They actually did a pretty good job.  Great digital
tools help us to make beautifully typeset documents, videos, music and many
more.  In general, computers helps us enormously in &lt;em&gt;doing&lt;/em&gt;, but I believe they
inhibit us in &lt;em&gt;thinking&lt;/em&gt;.  Most of our thinking &lt;a href="https://youtu.be/p2LZLYcu_JY?t=53m30s"&gt;involve figurative or imagery
terms&lt;/a&gt; and these &lt;a href="https://www.youtube.com/watch?v=agOdP2Bmieg"&gt;representations of thought&lt;/a&gt; are very
difficult to capture digitally.  The way we interface with digital tools is
simply too slow for doing fast iterations on a new vague idea that was just
born in our&amp;nbsp;head.&lt;/p&gt;
&lt;p&gt;Imagine you are working on a chart for your next presentation.  Take a pen and
a piece of paper and in only a couple of minutes you can record five different
versions your idea of that figure.  You discard three because you can see
immediately that they don&amp;#8217;t communicate what you wish to express.  In the next
minute you realize that the remaining two versions could be combined into a
completely new one you hadn&amp;#8217;t considered before!  In less then five minutes the
sixth version of your graph must be something solid.  Maybe not perfect, but
it&amp;#8217;s worth transforming your sketch into a digital figure.  If you skip the
initial paper sketches, how far do you get in PowerPoint in five minutes?  I&amp;#8217;m
usually browsing on a support forum trying to figure out how to do a certain
operation.  If I&amp;#8217;m lucky I get fancy bar chart in half an hour.  I don&amp;#8217;t like
it, but I&amp;#8217;m already &lt;em&gt;out of ideas&lt;/em&gt; how to make it&amp;nbsp;better.&lt;/p&gt;
&lt;p&gt;When we find, for example, an influential talk on YouTube with meticulously
prepared slides, what we see is the linear, condensed end result of a very
personal, mostly non-linear thinking process.  What we tend to forget is that
&lt;em&gt;creating&lt;/em&gt; is exactly that process and not the act of typing the next slide in&amp;nbsp;PowerPoint.&lt;/p&gt;
&lt;p&gt;I believe that in spite of the tremendous success of digitalization the
&lt;em&gt;thinking&lt;/em&gt; is still better done offline, with pen and paper.  I find that these
simple tools allow me to record and process my ideas the fastest.  I cannot
show off &lt;a href="https://lifehacker.com/the-bullet-journal-minus-the-hype-is-actually-a-reall-1786382012"&gt;beautifully decorated Moleskin notebooks&lt;/a&gt; with charts
and diagrams.  I mainly scribble, draw boxes and potato-shaped thingies then I
connect them with&amp;nbsp;lines.&lt;/p&gt;
&lt;p&gt;If you &lt;a href="https://en.wikipedia.org/wiki/Knowledge_worker"&gt;think for a living&lt;/a&gt;, think paper.  Don&amp;#8217;t stare at
your big computer screens and try to come up with something smart by pressing
some keys and clicking around.  Get a piece of paper and record your thoughts
with a pen.  Draw, write, doodle.  Give your ideas a structure on paper first
then use digital tools after some initial iterations and&amp;nbsp;reflection.&lt;/p&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="misc"/></entry><entry><title>Minimum Coin Exchange</title><link href="https://thewagner.net/blog/2018/04/30/minimum-coin-exchange/" rel="alternate"/><published>2018-04-30T00:00:00+02:00</published><updated>2018-04-30T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2018-04-30:/blog/2018/04/30/minimum-coin-exchange/</id><summary type="html">&lt;p&gt;I solve the Minimum Coin Exchange problem programmatically using Haskell.
I will compare the performance of the naive implementation to that using
dynamic&amp;nbsp;programming.&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this post I solve the Minimum Coin Exchange problem programmatically using
Haskell.  I will compare the performance of the naive implementation to that
using dynamic&amp;nbsp;programming.&lt;/p&gt;
&lt;h1&gt;The&amp;nbsp;problem&lt;/h1&gt;
&lt;p&gt;The minimum coin exchange problem is &lt;a href="http://www.algorithmist.com/index.php/Min-Coin_Change"&gt;generally asked&lt;/a&gt;: if we want to make
change&amp;nbsp;for &lt;span class="math"&gt;\(N\)&lt;/span&gt; cents, and we have infinite supply of each&amp;nbsp;of
&lt;span class="math"&gt;\(S=\{S_{0},S_{2},\ldots ,S_{m-1}\}\)&lt;/span&gt;
valued coins, what is the least amount of coins we need to make the&amp;nbsp;change?&lt;/p&gt;
&lt;p&gt;The solution can be found in a recursive manner where at each step of the
recursion we have two&amp;nbsp;options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;we use&amp;nbsp;the &lt;span class="math"&gt;\(S_m\)&lt;/span&gt; valued coin in the change and we try to find the change&amp;nbsp;for &lt;span class="math"&gt;\(N - S_m\)&lt;/span&gt; cents with the same set of&amp;nbsp;coins.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;we decide not to use&amp;nbsp;the &lt;span class="math"&gt;\(S_m\)&lt;/span&gt; valued coin in the change: we keep on looking
   for a change&amp;nbsp;of &lt;span class="math"&gt;\(N\)&lt;/span&gt; cents&amp;nbsp;with &lt;span class="math"&gt;\(m-1\)&lt;/span&gt; coins&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At each step we need to choose the option that uses less coins.  It is expected
that this process will end after finite number of steps because either the
number of coins or the money to change decreases at each&amp;nbsp;step.&lt;/p&gt;
&lt;p&gt;On the &lt;a href="http://www.algorithmist.com/index.php/Min-Coin_Change"&gt;algorithmist.com&lt;/a&gt; we find a succinct recursive formula to describe
this&amp;nbsp;process&lt;/p&gt;
&lt;div class="math"&gt;$$
C(N,m)=\min {(C(N - S_{m}, m) + 1, C(N, m-1))}
$$&lt;/div&gt;
&lt;p&gt;the arguments of&amp;nbsp;the &lt;span class="math"&gt;\(\min\)&lt;/span&gt; function correspond to the two options described
above.&amp;nbsp;The &lt;span class="math"&gt;\(+1\)&lt;/span&gt; in the first argument shows that choosing that option will
increase the number of coins in the change.  The recursive formula is completed
with the base&amp;nbsp;cases:&lt;/p&gt;
&lt;div class="math"&gt;$$
\begin{align}
C(N,m) &amp;amp;= 0,      &amp;amp; N=0              \\
C(N,m) &amp;amp;= \infty, &amp;amp; N&amp;lt;0              \\
C(N,m) &amp;amp;= \infty, &amp;amp; N\geq 1, m\leq 0 \\
\end{align}
$$&lt;/div&gt;
&lt;p&gt;If the result&amp;nbsp;of &lt;span class="math"&gt;\(C(N,m)\)&lt;/span&gt; is&amp;nbsp;either &lt;span class="math"&gt;\(0\)&lt;/span&gt; or &lt;span class="math"&gt;\(\infty\)&lt;/span&gt; then it is impossible make
change&amp;nbsp;for &lt;span class="math"&gt;\(N\)&lt;/span&gt; with the given coins.  The case (1) applies when we successfully&amp;nbsp;changed &lt;span class="math"&gt;\(N\)&lt;/span&gt; with the given coins. Case (2) means that our smallest valued coin
is larger than the amount for which the change is requested.  Finally (3)
represents the situation where we cannot pick any more coin to complete the&amp;nbsp;change.&lt;/p&gt;
&lt;p&gt;For simplicity, we will use a fixed set of&amp;nbsp;coins: &lt;span class="math"&gt;\([25, 20, 10, 5, 1]\)&lt;/span&gt;.  For
example, the minimum number of coins needed for 40 cents using the formulation
above is given&amp;nbsp;by &lt;span class="math"&gt;\(C(40, 4)\)&lt;/span&gt;.  Also note that we only compute the number of
coins, we don&amp;#8217;t give the exact denominators to be used in the&amp;nbsp;change.&lt;/p&gt;
&lt;h1&gt;Foundations&lt;/h1&gt;
&lt;p&gt;As we use a fixed set of coins we hard-code the available coin&amp;nbsp;denominators:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Available coin denominators.&lt;/span&gt;
&lt;span class="nf"&gt;coins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;coins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We will write a function with the following&amp;nbsp;signature:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;-- amount&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;-- index of the last available coin&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Change&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- the number of coins&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;change&lt;/code&gt; takes to arguments: the amount to change, the index of the last
available coin and it returns the number of coins in the&amp;nbsp;change.&lt;/p&gt;
&lt;p&gt;Taking a list index as the second argument is, of course, very error prone: our
program will crash if we try to address an element that is not present in&amp;nbsp;the
&lt;code&gt;coins&lt;/code&gt; list.  We ignore this deficency in order to stay as close as possible
to the theoretical formulation of the&amp;nbsp;problem.&lt;/p&gt;
&lt;p&gt;Since there are cases where the change is impossible, we choose the result&amp;nbsp;type
&lt;code&gt;Change&lt;/code&gt; as&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is more expressive than using infinity as a sentinel value when the change
is not&amp;nbsp;possible.&lt;/p&gt;
&lt;p&gt;With this preparation we are ready to implement the first version&amp;nbsp;of &lt;code&gt;change&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Naive&amp;nbsp;implementation&lt;/h1&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Naive implementation using the recursive formula from:&lt;/span&gt;
&lt;span class="c1"&gt;-- http://www.algorithmist.com/index.php/Min-Coin_Change&lt;/span&gt;
&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Change&lt;/span&gt;
&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Nothing&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Nothing&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;otherwise&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;minOf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;fmap&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This implementation is &lt;em&gt;almost&lt;/em&gt; maps one-to-one to the recursive formula above.
The first three guard expression handle the three base cases.  In the last
clause the function calls itself to solve the two sub-problems which I&amp;nbsp;called &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Choosing &lt;code&gt;Maybe&lt;/code&gt; to represent the&amp;nbsp;result &lt;code&gt;Change&lt;/code&gt; forces us to deviate from the
clean mathematical formulation at two&amp;nbsp;places:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;we&amp;nbsp;use &lt;code&gt;fmap&lt;/code&gt; to&amp;nbsp;add &lt;code&gt;1&lt;/code&gt; to the result of&amp;nbsp;the &lt;code&gt;left&lt;/code&gt; subproblem&lt;/li&gt;
&lt;li&gt;we use our&amp;nbsp;own &lt;code&gt;minOf&lt;/code&gt; function instead of the&amp;nbsp;built-in &lt;code&gt;min&lt;/code&gt; function&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first point is easy: we cannot add&amp;nbsp;an &lt;code&gt;Int&lt;/code&gt; to&amp;nbsp;a &lt;code&gt;Maybe Int&lt;/code&gt; because their
types don&amp;#8217;t match.&amp;nbsp;Since &lt;code&gt;Maybe Int&lt;/code&gt; is a functor so we can&amp;nbsp;use &lt;code&gt;fmap&lt;/code&gt; to lift
the addition into the context&amp;nbsp;of &lt;code&gt;Maybe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As for the second point, let&amp;#8217;s see the implementation&amp;nbsp;of &lt;code&gt;minOf&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;Control.Applicative&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;|&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nf"&gt;minOf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Change&lt;/span&gt;
&lt;span class="nf"&gt;minOf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;minOf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;|&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The function takes&amp;nbsp;two &lt;code&gt;Change&lt;/code&gt; values:  if&amp;nbsp;both &lt;code&gt;Maybe&lt;/code&gt; contain &lt;code&gt;Int&lt;/code&gt; values
we choose the smaller one.  Otherwise we try to keep the one that has a value
in it&amp;nbsp;using &lt;code&gt;&amp;lt;|&amp;gt;&lt;/code&gt;.  This behaves similarly to logical &lt;span class="caps"&gt;OR&lt;/span&gt;.  We can easily test
this&amp;nbsp;in &lt;code&gt;ghci&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Prelude&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;import&lt;span class="w"&gt; &lt;/span&gt;Control.Applicative
Prelude&lt;span class="w"&gt; &lt;/span&gt;Control.Applicative&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Just&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="p"&gt;|&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Nothing&lt;span class="w"&gt;  &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;keeps&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;first
Just&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
Prelude&lt;span class="w"&gt; &lt;/span&gt;Control.Applicative&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Nothing&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="p"&gt;|&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Just&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;keeps&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;second
Just&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
Prelude&lt;span class="w"&gt; &lt;/span&gt;Control.Applicative&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Nothing&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="p"&gt;|&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Nothing&lt;span class="w"&gt; &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;returns&lt;span class="w"&gt; &lt;/span&gt;Nothing
Nothing
Prelude&lt;span class="w"&gt; &lt;/span&gt;Control.Applicative&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Just&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="p"&gt;|&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;Just&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;prefers&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;first
Just&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This implementation&amp;nbsp;of &lt;code&gt;minOf&lt;/code&gt; gives us the right behavior when we select the
smaller between the results of&amp;nbsp;the &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt; subproblems.&lt;/p&gt;
&lt;p&gt;The&amp;nbsp;built-in &lt;code&gt;min&lt;/code&gt; can actually operate&amp;nbsp;on &lt;code&gt;Maybe Int&lt;/code&gt; values.  We just cannot
use it here because it&amp;nbsp;returns &lt;code&gt;Nothing&lt;/code&gt; if &lt;em&gt;any&lt;/em&gt; of its argument&amp;nbsp;is &lt;code&gt;Nothing&lt;/code&gt;.
This would terminate our recursive function without exploring the whole
solution&amp;nbsp;space.&lt;/p&gt;
&lt;p&gt;We could almost directly implement the terse mathematical solution as a
recursive function.  Overall our function is short and readable, but before we
open the champagne and celebrate let&amp;#8217;s see how our solution&amp;nbsp;performs.&lt;/p&gt;
&lt;h1&gt;Performance of the naive&amp;nbsp;solution&lt;/h1&gt;
&lt;p&gt;We can use the microbenchmarking library &lt;a href="http://www.serpentine.com/criterion/"&gt;criterion&lt;/a&gt; to measure the running
time of the&amp;nbsp;naive &lt;code&gt;change&lt;/code&gt; implementation.  Let&amp;#8217;s see how the running time
depends on the amount to change.  The following table shows the approximate
time of computing the change for 40, 100, 150 and 200&amp;nbsp;cents.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: right;"&gt;Amount [cents]&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Running time [ms]&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;40&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;100&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.344&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;150&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1.420&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;200&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4.025&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The running time of the naive solution scales polynomially with the number of
cents.  Let&amp;#8217;s try to improve&amp;nbsp;this!&lt;/p&gt;
&lt;h1&gt;Implementation using dynamic&amp;nbsp;programming&lt;/h1&gt;
&lt;p&gt;The recursive method of the minimum coin exchange problem combines the
solutions of subproblems with smaller amounts to change.  We could optimize our
naive solution using &lt;a href="https://en.wikipedia.org/wiki/Dynamic_programming"&gt;dynamic programming&lt;/a&gt;.  The idea is that every time we
solve a subproblem we memorize its solution.  The next time the same subproblem
occurs, instead of recomputing its solution we look up the previously solved&amp;nbsp;solution.&lt;/p&gt;
&lt;p&gt;We write a new&amp;nbsp;function &lt;code&gt;changeD&lt;/code&gt; which represents a stateful computation.  The
state is a map from problem parameters to its solution.  In our case, a map
from pair of integers (the denominator index and the amount) to&amp;nbsp;a &lt;code&gt;Change&lt;/code&gt;
value.  We call this&amp;nbsp;computation &lt;code&gt;Dyn&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;qualified&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;Data.Map.Strict&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;Control.Monad.Trans.State&lt;/span&gt;

&lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Dyn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;M&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Change&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using this, we can&amp;nbsp;write &lt;code&gt;changeD&lt;/code&gt; which, returns&amp;nbsp;a &lt;code&gt;Dyn&lt;/code&gt; computation resulting
in&amp;nbsp;a &lt;code&gt;Change&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;changeD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Dyn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Change&lt;/span&gt;
&lt;span class="nf"&gt;changeD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Nothing&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Nothing&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;otherwise&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memorize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;memorize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;minOf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The code looks very much like the naive solution but, since we&amp;#8217;re operating in&amp;nbsp;the &lt;code&gt;Dyn&lt;/code&gt; context, we are using&amp;nbsp;the &lt;code&gt;do&lt;/code&gt; notation.&amp;nbsp;The &lt;code&gt;memorize&lt;/code&gt; computation
implements the storing and recalling the subproblems&amp;#8217;&amp;nbsp;solution:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;memorize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Dyn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Change&lt;/span&gt;
&lt;span class="nf"&gt;memorize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;M&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- try to recall the solution&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kr"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;of&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;-- return previously stored solution&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kt"&gt;Nothing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;changeD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;-- compute the solution&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;modify&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;M&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;-- store the solution&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function is a literal implementation of the dynamic programming method.
We try to look up the solution in the state: if the subproblem has already been
solved we return the solution, otherwise we solve the subproblem and store its
solution in the&amp;nbsp;state.&lt;/p&gt;
&lt;p&gt;The final step is to&amp;nbsp;provide &lt;code&gt;change&lt;/code&gt; in a form identical to the naive&amp;nbsp;solution:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Change&lt;/span&gt;
&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;evalState&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;changeD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;M&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We execute&amp;nbsp;the &lt;code&gt;Dyn&lt;/code&gt; computation&amp;nbsp;using &lt;code&gt;evalState&lt;/code&gt; by providing an initial
empty state.  This function provides exactly the same interface as the naive
version above.  The two implementations can be used interchangeably.  Let&amp;#8217;s
which of the two implementations is worth&amp;nbsp;using.&lt;/p&gt;
&lt;h1&gt;Naive vs&amp;nbsp;dynamic&lt;/h1&gt;
&lt;p&gt;The table below compares the running times of the two implementations as a
function of the amount to&amp;nbsp;change.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: right;"&gt;Amount [cents]&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Running time (naive) [ms]&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Running time (dynamic) [ms]&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;40&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.026&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.117&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;100&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.344&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.354&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;150&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1.420&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.556&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;200&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4.025&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.814&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The dynamic programming version scales linearly with the amount to change.  The
difference in running time becomes significant for amounts larger than 100
cents.  As always, this speedup didn&amp;#8217;t come for free: we traded running speed
for storage&amp;nbsp;space.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;The minimum coin exchange problem is a classic example demonstrating dynamic
programming.  We implemented a solution by naively transcribing the proposed
recursive formula almost literally to Haskell.  We then used dynamic
programming to improve time complexity of the naive solution.  The dynamic
programming method was encapsulated in&amp;nbsp;a &lt;code&gt;Dyn&lt;/code&gt; computation where the solutions
to already solved subproblems are stored in a&amp;nbsp;map.&lt;/p&gt;
&lt;p&gt;The code for both implementations can be found &lt;a href="https://github.com/wagdav/dynamic-programming/tree/master/src/Coin"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="misc"/></entry><entry><title>Knowing Algorithms</title><link href="https://thewagner.net/blog/2018/03/10/knowing-algorithms/" rel="alternate"/><published>2018-03-10T00:00:00+01:00</published><updated>2018-03-10T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2018-03-10:/blog/2018/03/10/knowing-algorithms/</id><summary type="html">&lt;p&gt;The other day I got a question from a colleague:  &lt;em&gt;Do you know an algorithm for
this problem of &amp;#8230; details&amp;#8230;details?&lt;/em&gt;  The exact the problem description is
not important.  It was a well defined problem which totally made sense.  I felt
that there must be an algorithm for it, but …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The other day I got a question from a colleague:  &lt;em&gt;Do you know an algorithm for
this problem of &amp;#8230; details&amp;#8230;details?&lt;/em&gt;  The exact the problem description is
not important.  It was a well defined problem which totally made sense.  I felt
that there must be an algorithm for it, but I couldn&amp;#8217;t help.  I just simply
didn&amp;#8217;t &lt;em&gt;know&lt;/em&gt;&amp;nbsp;any.&lt;/p&gt;
&lt;p&gt;I didn&amp;#8217;t have a formal training on algorithms and complexity.  Yes, I can
easily write&amp;nbsp;an &lt;span class="math"&gt;\(\mathcal{O}(n^2)\)&lt;/span&gt; sorting algorithm.  Probably I can even make&amp;nbsp;it &lt;span class="math"&gt;\(\mathcal{O}(n \log n)\)&lt;/span&gt;, but I wouldn&amp;#8217;t enjoy it.  Of course, I quickly
learned that I shouldn&amp;#8217;t write my own sorting algorithm.  Countless hours of
thinking went into inventing, refining all sorts of algorithms so I better
reach for libraries written by smart people and use those&amp;nbsp;instead.&lt;/p&gt;
&lt;p&gt;Most programming languages provide basic algorithms such as finding the minimum
or maximum element in a sequence, sorting and so on.  Sometimes we can get away
with these &amp;#8220;built-in&amp;#8221; algorithms, but often we need to provide a more complex
solution.  In real world problems data are noisy, things can fail and just
nothing is as simple as in textbook&amp;nbsp;examples.&lt;/p&gt;
&lt;p&gt;We may try to combine the provided basic algorithms as building blocks to solve
our particular problem.  Sounds reasonable, right?  &lt;em&gt;Tackle complexity by
composition&lt;/em&gt; the mantra says.  But if you&amp;#8217;re&amp;nbsp;given &lt;code&gt;erase&lt;/code&gt; and &lt;code&gt;remove_if&lt;/code&gt; to
eliminate elements that fulfill a certain criterion from a C++ container, would
you come up with the &lt;a href="https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom"&gt;Erase-remove idiom&lt;/a&gt;?  I wouldn&amp;#8217;t.  For example, in the
talk &lt;a href="https://www.youtube.com/watch?v=eidEEmGLQcU"&gt;&lt;span class="caps"&gt;STL&lt;/span&gt; Algorithms in Action from CppCon 2015&lt;/a&gt; Michael VanLoon solves
interesting sorting problems using components from&amp;nbsp;the &lt;code&gt;&amp;lt;algorithm&amp;gt;&lt;/code&gt; library.
None of those solutions are&amp;nbsp;trivial.&lt;/p&gt;
&lt;p&gt;Building algorithms is hard, even if you have the basic components available.
It takes special expertise and a lot of time.  I don&amp;#8217;t have this expertise, but
I still want to help my colleagues to solve their domain specific&amp;nbsp;problem.&lt;/p&gt;
&lt;p&gt;The point Nicolas Ormrod makes in his great talk &lt;a href="https://www.youtube.com/watch?v=YA-nB2wjVcI"&gt;Fantastic Algorithms and
Where To Find Them&lt;/a&gt;, is that algorithms are &lt;em&gt;tools&lt;/em&gt;: you need to know they
exist and you need to be able to use them.  It doesn&amp;#8217;t matter if you built the
tool yourself (which is still very impressive), but how many different problems
you can solve with it.  The more tools you have in your toolbox, the more
algorithms you know, the more problems you can&amp;nbsp;solve.&lt;/p&gt;
&lt;p&gt;One of piece of advice the book &lt;a href="https://en.wikipedia.org/wiki/The_Pragmatic_Programmer"&gt;The Pragmatic Programmer&lt;/a&gt; gives (section
&lt;em&gt;Your Knowledge Portfolio&lt;/em&gt; in Chapter 1) is that you should learn at least one
new programming language every year.  I&amp;#8217;d say you should also learn a new
algorithm every month.  So next time when you&amp;#8217;re asked if you know an algorithm
that solves a certain problem you can reach into your toolbox and answer:
&lt;em&gt;yeah, this algorithm can solve a problem which looks very similar to yours,
maybe it would be a good&amp;nbsp;fit&amp;#8230;&lt;/em&gt;&lt;/p&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="misc"/></entry><entry><title>Concurrency Patterns</title><link href="https://thewagner.net/blog/2018/02/26/concurrency-patterns/" rel="alternate"/><published>2018-02-26T00:00:00+01:00</published><updated>2018-02-26T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2018-02-26:/blog/2018/02/26/concurrency-patterns/</id><summary type="html">&lt;p&gt;In this post I&amp;#8217;m replicating in Haskell some of the examples from the talk &lt;a href="https://talks.golang.org/2012/concurrency.slide"&gt;Go
Concurrency Patterns&lt;/a&gt; by Rob Pike.  In the talk Pike explains how Go&amp;#8217;s
built-in concurrency primitives can help writing concurrent code.  I was
curious to see how the presented examples would look in Haskell …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this post I&amp;#8217;m replicating in Haskell some of the examples from the talk &lt;a href="https://talks.golang.org/2012/concurrency.slide"&gt;Go
Concurrency Patterns&lt;/a&gt; by Rob Pike.  In the talk Pike explains how Go&amp;#8217;s
built-in concurrency primitives can help writing concurrent code.  I was
curious to see how the presented examples would look in Haskell, a language
that I&amp;#8217;m interested in&amp;nbsp;learning.&lt;/p&gt;
&lt;h1&gt;Simulating a search&amp;nbsp;engine&lt;/h1&gt;
&lt;p&gt;The example we are going to play with (again, taken from Pike&amp;#8217;s presentation)
is a simulated search engine.  The search engine receives a search query and
returns web, image and video&amp;nbsp;results.&lt;/p&gt;
&lt;p&gt;We start with a simple implementation where the different kinds of search are
performed sequentially, then we gradually add concurrency to build a better
performing search&amp;nbsp;engine.&lt;/p&gt;
&lt;p&gt;First we&amp;#8217;re going to need some imports and some data types to represent our&amp;nbsp;problem.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;Control.Concurrent.Async&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mapConcurrently&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;race&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;Control.Concurrent&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;threadDelay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Random&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getStdRandom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;randomR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;System.Timeout&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;Text.Printf&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;

&lt;span class="kr"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchKind&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Image&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Web&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Video&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;deriving&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Show&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We represent the search query with a simple string and the kinds of search we
can perform with product-type.  The role of the imported functions will be
clear as we go&amp;nbsp;along.&lt;/p&gt;
&lt;p&gt;This is already enough to get us started.  We can write a fake search function
which takes&amp;nbsp;a &lt;code&gt;SearchQuery&lt;/code&gt;,&amp;nbsp;a &lt;code&gt;SearchKind&lt;/code&gt; and returns an &lt;span class="caps"&gt;IO&lt;/span&gt; action which, when
run, yields the search result as a&amp;nbsp;string:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- https://talks.golang.org/2012/concurrency.slide#43&lt;/span&gt;
&lt;span class="nf"&gt;fakeSearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchKind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="nf"&gt;fakeSearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;delayMs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getStdRandom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;randomR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;threadDelay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;microseconds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;delayMs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- simulating random work&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s results for &amp;#39;%s&amp;#39; in %d ms&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;delayMs&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;microseconds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Our search back-end won&amp;#8217;t get any more sophisticated than&amp;nbsp;this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;we make the current thread sleep for a random number amount of milliseconds,&amp;nbsp;then&lt;/li&gt;
&lt;li&gt;we return the simulated search&amp;nbsp;results.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The resulting string contains the input parameters and the time it took to
serve this request.  We want to print these results so we write a small helper&amp;nbsp;function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Helper function to print the results&lt;/span&gt;
&lt;span class="nf"&gt;printResults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;printResults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;of&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;Nothing&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;putStrLn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;timed out&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function takes an optional list of strings and prints them on the console.
If the argument&amp;nbsp;is &lt;code&gt;Nothing&lt;/code&gt; it means that the search request timed out (we
will see this later).  At this stage this function looks more generic than it
needs to be.  Probably you would start with a simpler signature, something&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;printResults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and make it more complex &lt;a href="https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it"&gt;when needed&lt;/a&gt;.  This would make more sense and I
also started with this initially.  However, for the sake of this post, we will
use the more generic version above so we can re-use it in the subsequent&amp;nbsp;examples.&lt;/p&gt;
&lt;h1&gt;Search&amp;nbsp;1.0&lt;/h1&gt;
&lt;p&gt;The first version of our search engine will perform the image, web and video
searches&amp;nbsp;sequentially:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Run the Web, Image, and Video searches sequentally&lt;/span&gt;
&lt;span class="c1"&gt;-- https://talks.golang.org/2012/concurrency.slide#45&lt;/span&gt;
&lt;span class="nf"&gt;search10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;search10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mapM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fakeSearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printResults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;nbsp;use &lt;code&gt;mapM&lt;/code&gt; to sequentially perform the three kinds of searches.  The result
of a typical search&amp;nbsp;using &lt;code&gt;haskell&lt;/code&gt; as a query would look&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="go"&gt;[&amp;quot;Web results for &amp;#39;haskell&amp;#39; in 27 ms&amp;quot;,&lt;/span&gt;
&lt;span class="go"&gt; &amp;quot;Image results for &amp;#39;haskell&amp;#39; in 61 ms&amp;quot;,&lt;/span&gt;
&lt;span class="go"&gt; &amp;quot;Video results for &amp;#39;haskell&amp;#39; in 17 ms&amp;quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since the searches are performed sequentially it takes 27 + 61 + 17 = 105 ms to
serve the results to the user.  This post won&amp;#8217;t be about concurrency if we were
to stop&amp;nbsp;here.&lt;/p&gt;
&lt;h1&gt;Search&amp;nbsp;2.0&lt;/h1&gt;
&lt;p&gt;We can speed things up if we can send the three kinds of queries to our
back-end servers independently and wait for the results to come back.  We need
to change one (!) function in our code to arrive to the next version of our
search&amp;nbsp;engine:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Run the Web, Image, and Video searches concurrently, and wait for all&lt;/span&gt;
&lt;span class="c1"&gt;-- results.&lt;/span&gt;
&lt;span class="c1"&gt;-- https://talks.golang.org/2012/concurrency.slide#47&lt;/span&gt;
&lt;span class="nf"&gt;search20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;search20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mapConcurrently&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fakeSearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printResults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;mapConcurrently&lt;/code&gt; combinator from the &lt;a href="http://hackage.haskell.org/package/async-2.2.1/docs/Control-Concurrent-Async.html#v:mapConcurrently"&gt;async&lt;/a&gt; library will launch three
light-weight threads and perform the three search actions concurrently.  The
output of the program is similar (clearly the random timings will change), but
it runs faster.  The running time will be limited by the &lt;em&gt;slowest&lt;/em&gt; search&amp;nbsp;query.&lt;/p&gt;
&lt;p&gt;We get a completely different behavior, but our code has the same structure as
the sequential version.  We don&amp;#8217;t have to use locks, mutexes, callbacks, etc.,
the code clearly expresses our intent.  It feels like we got concurrency &lt;em&gt;for
free&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;Search&amp;nbsp;2.1&lt;/h1&gt;
&lt;p&gt;The concurrent version performs really well, but there might be cases where the
slowest request would be very slow for some reason.  Users get angry if things
are slow, so we&amp;#8217;d better display an error message if we cannot display a
results within a given amount of&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;We introduce a maximum delay (80 ms in this example): if the slowest request
takes longer then this, instead of the search results, we display a &amp;#8220;timed out&amp;#8221;
message and we send our sincerest apologies to our&amp;nbsp;user.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Don&amp;#39;t wait for slow servers&lt;/span&gt;
&lt;span class="c1"&gt;-- https://talks.golang.org/2012/concurrency.slide#47&lt;/span&gt;
&lt;span class="nf"&gt;maxDelay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;
&lt;span class="nf"&gt;maxDelay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- us&lt;/span&gt;

&lt;span class="nf"&gt;search21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;search21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maxDelay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mapConcurrently&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fakeSearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printResults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Again, we only have to do a small modification to get the desired behavior.
The search actions are wrapped in&amp;nbsp;a &lt;code&gt;timeout&lt;/code&gt; call.  The signature of this
function&amp;nbsp;is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;-- maximum delay in microseconds&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;-- the action to perform&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;-- (Just a) if less than the delay elapsed else Nothing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can run this version a couple of times and we will see two kinds of outputs.
If all requests take less than&amp;nbsp;80ms &lt;code&gt;printResults&lt;/code&gt; will behave as&amp;nbsp;before:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;[&lt;span class="s2"&gt;&amp;quot;Web results for &amp;#39;haskell&amp;#39; in 70 ms&amp;quot;&lt;/span&gt;,
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Web results for &amp;#39;haskell&amp;#39; in 67 ms&amp;quot;&lt;/span&gt;,
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Video results for &amp;#39;haskell&amp;#39; in 63 ms&amp;quot;&lt;/span&gt;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;otherwise, and this is&amp;nbsp;why &lt;code&gt;printResults&lt;/code&gt; takes&amp;nbsp;a &lt;code&gt;Maybe [String]&lt;/code&gt; as&amp;nbsp;input,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;timed out
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;is&amp;nbsp;printed.&lt;/p&gt;
&lt;h1&gt;Search&amp;nbsp;3.0&lt;/h1&gt;
&lt;p&gt;We can still do better.  The occasional timeout messages are still annoying.
We won&amp;#8217;t be too popular if our search website times out too often.  It&amp;#8217;s also a
waste to discard all the results from slow servers.  Maybe only the video
search is slow, but we still throw away the web and image&amp;nbsp;results.&lt;/p&gt;
&lt;p&gt;We can use replication to reduce the chance of a timeout.  We will send the
request to two sets of back-end servers, two replicas.  If one replica has some
problem and responds slowly we can still get back a response from the&amp;nbsp;other.&lt;/p&gt;
&lt;p&gt;We write a&amp;nbsp;function &lt;code&gt;fastest&lt;/code&gt; that does exactly&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- https://talks.golang.org/2012/concurrency.slide#48&lt;/span&gt;
&lt;span class="nf"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchKind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="nf"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;race&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fakeSearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- server 1&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fakeSearch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- server 2&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;of&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;Left&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Server1: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;Right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Server2: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function have the same interface&amp;nbsp;as &lt;code&gt;fakesearch&lt;/code&gt; but internally it sends
the same query two times to two different servers and keeps the result from the
fastest.&amp;nbsp;The &lt;code&gt;race&lt;/code&gt; combinator from the &lt;a href="http://hackage.haskell.org/package/async-2.2.1/docs/Control-Concurrent-Async.html#v:race"&gt;async&lt;/a&gt;&amp;nbsp;library:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;race&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Either&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;helps us to achieve this.  It launches the two &lt;span class="caps"&gt;IO&lt;/span&gt; actions in parallel and keeps
the result from the fastest.  The other action will be terminated.  There is no
second price in this race.  The return value will indicate which action won.
We prepend the server name to our search result to be able to see where it was
served&amp;nbsp;from.&lt;/p&gt;
&lt;p&gt;We now replace&amp;nbsp;the &lt;code&gt;fakeSearch&lt;/code&gt; call&amp;nbsp;with &lt;code&gt;fastest&lt;/code&gt; and we&amp;nbsp;get:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Send requests to multiple replicas and use the first response&lt;/span&gt;
&lt;span class="c1"&gt;-- https://talks.golang.org/2012/concurrency.slide#50&lt;/span&gt;
&lt;span class="nf"&gt;search30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;SearchQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;search30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;maxDelay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mapConcurrently&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fastest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Web&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;printResults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;#8217;s see some typical&amp;nbsp;results:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;search30
&lt;span class="go"&gt;[&amp;quot;Server1: Web results for &amp;#39;haskell&amp;#39; in 29 ms&amp;quot;,&lt;/span&gt;
&lt;span class="go"&gt; &amp;quot;Server1: Image results for &amp;#39;haskell&amp;#39; in 36 ms&amp;quot;,&lt;/span&gt;
&lt;span class="go"&gt; &amp;quot;Server2: Video results for &amp;#39;haskell&amp;#39; in 49 ms&amp;quot;]&lt;/span&gt;

&lt;span class="gp"&gt;$ &lt;/span&gt;search30
&lt;span class="go"&gt;[&amp;quot;Server2: Web results for &amp;#39;haskell&amp;#39; in 19 ms&amp;quot;,&lt;/span&gt;
&lt;span class="go"&gt; &amp;quot;Server2: Image results for &amp;#39;haskell&amp;#39; in 50 ms&amp;quot;,&lt;/span&gt;
&lt;span class="go"&gt; &amp;quot;Server1: Video results for &amp;#39;haskell&amp;#39; in 39 ms&amp;quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can see that in the first run the web and image results were served by the
first replica, while the video result comes from the second.  In the second
example the first replica served the video results and the second replica the
other two.  Any combination is possible, these are just results from two&amp;nbsp;runs.&lt;/p&gt;
&lt;p&gt;With the version 3.0 we can serve the results of all three searches with very
high probability within 80&amp;nbsp;ms.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;As &lt;a href="https://talks.golang.org/2012/concurrency.slide#52"&gt;Rob Pike puts it&lt;/a&gt;, with a few transformations we converted&amp;nbsp;a&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;slow&lt;/li&gt;
&lt;li&gt;sequential&lt;/li&gt;
&lt;li&gt;failure-sensitive&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;program into one that&amp;nbsp;is&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fast&lt;/li&gt;
&lt;li&gt;concurrent&lt;/li&gt;
&lt;li&gt;replicated&lt;/li&gt;
&lt;li&gt;robust&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was surprised to see how little the code structure changed in the Haskell
versions.  We significantly changed the behavior of the program without
compromising the readability.  We didn&amp;#8217;t have to use locks and mutexes, but we
could focus on the intent, &lt;em&gt;what&lt;/em&gt; the program should do, thanks to the powerful
libraries and the run-time&amp;nbsp;system.&lt;/p&gt;
&lt;p&gt;I recommend to watch &lt;a href="http://www.youtube.com/watch?v=f6kdp27TYZs"&gt;the original talk on YouTube&lt;/a&gt; and to further compare
the Haskell and the Go implementations.  You can find the code
&lt;a href="https://github.com/wagdav/haskell-concurrency-patterns"&gt;here&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/></entry><entry><title>Working habits</title><link href="https://thewagner.net/blog/2016/07/20/working-habits/" rel="alternate"/><published>2016-07-20T00:00:00+02:00</published><updated>2016-07-20T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2016-07-20:/blog/2016/07/20/working-habits/</id><summary type="html">&lt;p&gt;Inarguably &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Getting_Things_Done"&gt;David Allen&amp;#8217;s Getting Things Done&lt;/a&gt; had the great influence on me in developing an efficient working routine.  I have implemented my own system based on the book which works well for me most of the times.  Interestingly, &lt;span class="caps"&gt;GTD&lt;/span&gt; also taught me what I should &lt;em&gt;not&lt;/em&gt; do, and when …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Inarguably &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Getting_Things_Done"&gt;David Allen&amp;#8217;s Getting Things Done&lt;/a&gt; had the great influence on me in developing an efficient working routine.  I have implemented my own system based on the book which works well for me most of the times.  Interestingly, &lt;span class="caps"&gt;GTD&lt;/span&gt; also taught me what I should &lt;em&gt;not&lt;/em&gt; do, and when things go less great I am noticing it in a short&amp;nbsp;time:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;em&gt;Maybe this should be a whole project rather than a&amp;nbsp;task?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Is this item is really&amp;nbsp;actionable?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Was there any progress on this project&amp;nbsp;recently?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&amp;#8230;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When these questions arise, it&amp;#8217;s an indication that something needs to be changed.  Actually, most of the time they signal that some &lt;em&gt;thinking&lt;/em&gt; is needed before&amp;nbsp;doing.&lt;/p&gt;
&lt;p&gt;A key aspect of getting things done is a distraction free environment.  You can have the best task system ever, if the phone always rings, message notifications pop up, projects will never move forward.  I&amp;#8217;d already recognized some points to improve in my working habits during my PhD, but I&amp;#8217;ve been trying to shape my working environment more consciously since I started working in&amp;nbsp;industry.&lt;/p&gt;
&lt;p&gt;Here are some tools I use, techniques I implemented during the last years to support a good &lt;span class="caps"&gt;GTD&lt;/span&gt; work flow.  Most of the my work happens before the computer, so some of the points following are rather&amp;nbsp;specific.&lt;/p&gt;
&lt;p&gt;So here are my tips (for myself and&amp;nbsp;you):&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Avoid&amp;nbsp;distractions&lt;/li&gt;
&lt;li&gt;Be&amp;nbsp;asynchronous&lt;/li&gt;
&lt;li&gt;Be&amp;nbsp;responsive&lt;/li&gt;
&lt;li&gt;Be&amp;nbsp;distributed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#8217;s see each point in&amp;nbsp;detail.&lt;/p&gt;
&lt;div class="section" id="avoid-distractions"&gt;
&lt;h2&gt;Avoid&amp;nbsp;distractions&lt;/h2&gt;
&lt;p&gt;As stated earlier this is the most important point.  Distractions destroy&amp;nbsp;productivity.&lt;/p&gt;
&lt;div class="section" id="solid-black-desktop"&gt;
&lt;h3&gt;Solid black&amp;nbsp;desktop&lt;/h3&gt;
&lt;p&gt;I used to tinker a lot with desktop widgets, I loved to put email notifications, clocks, cool backgrounds, nice window decorations, etc. on my desktop.  Now they are all gone, they&amp;#8217;re good for nothing but distractions.  My desktop has solid black color, no icons or anything at&amp;nbsp;all.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="tiling-is-great"&gt;
&lt;h3&gt;Tiling is&amp;nbsp;great&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;m using a tiling window manager (&lt;a class="reference external" href="http://xmonad.org"&gt;XMonad&lt;/a&gt;) which helps me to keep my applications organized.  I can only see the windows I need for what I&amp;#8217;m working on.  My task bar is very small and only shows the most essential&amp;nbsp;information.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="at-most-two-screens"&gt;
&lt;h3&gt;At most two&amp;nbsp;screens&lt;/h3&gt;
&lt;p&gt;These days it&amp;#8217;s common to have a workstation with two, three or even more screens.  I used to love screens a lot myself: the more the better, I thought.  It turns out that more screens just provide more space for&amp;nbsp;distractions.&lt;/p&gt;
&lt;blockquote&gt;
&lt;em&gt;On this screen I will always keep my mail client open.&lt;/em&gt;&lt;/blockquote&gt;
&lt;p&gt;I used to think.  Well, that&amp;#8217;s basically the same thing as having an annoying &amp;#8220;You&amp;#8217;ve got mail&amp;#8221; notification on the desktop. Very&amp;nbsp;annoying.&lt;/p&gt;
&lt;p&gt;At work, my workstation has two screens, which is sufficient for me. Two screen provides reasonable arrangements for most of my work flows.  For example I can&amp;nbsp;keep:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;code and&amp;nbsp;documentation,&lt;/li&gt;
&lt;li&gt;code and testing/debugging&amp;nbsp;outputs,&lt;/li&gt;
&lt;li&gt;browser and mail&amp;nbsp;client&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;comfortably next to each other.  At home I use my laptop without external screens.  Thanks to my window manager I can switch almost instantaneously between virtual desktops, so I don&amp;#8217;t feel limited by its relatively small, 12.5&amp;#8221;&amp;nbsp;screen.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="be-asynchronous"&gt;
&lt;h2&gt;Be&amp;nbsp;asynchronous&lt;/h2&gt;
&lt;p&gt;Most of these ideas I learned from a series of blog posts explaining &lt;a class="reference external" href="https://zachholman.com/posts/how-github-works/"&gt;How GitHub Works&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="prefer-email-to-phone"&gt;
&lt;h3&gt;Prefer email to&amp;nbsp;phone&lt;/h3&gt;
&lt;p&gt;I prefer email to phone.  Receiving an email is not a distraction for me (see my comment on email notifications above) while a phone call is.  I can read and answer emails when I want, at the time and location where I feel like dealing with&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;Of course there are good reasons to call: the feedback is immediate, the discussion is more personal, conveying a message may be easier.  Still, most people prefer to call because they fear that the other person might not read their emails or forget to answer.  Indeed, most people haven&amp;#8217;t got the slightest clue how to deal with their email.  The result is: emails get lost and forgotten so people think &lt;em&gt;Maybe I should just call&amp;nbsp;instead&amp;#8230;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Calls and email can co-exist very naturally: calls can be organized over email.  Fix a time then discuss what&amp;#8217;s needed.  In fact, this way the phone call effectively turns into a meeting.  More on meetings in the next&amp;nbsp;section.&lt;/p&gt;
&lt;p&gt;Also email is only good as a communication tool if emails get answered, that is if the use of email comes with certain responsiveness.  I&amp;#8217;ll return to this point too&amp;nbsp;later.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="prefer-documentation-to-meetings"&gt;
&lt;h3&gt;Prefer documentation to&amp;nbsp;meetings&lt;/h3&gt;
&lt;p&gt;Just Google the terms &amp;#8220;why meetings are bad&amp;#8221; or &amp;#8220;how to have good meetings&amp;#8221; and you&amp;#8217;ll see my point.  The bottom line is that meetings are super expensive and very&amp;nbsp;inefficient.&lt;/p&gt;
&lt;p&gt;When I need to distribute knowledge I prefer to write documentation.  No, not that kind of documentation everybody hates writing.  I write a couple of lines on our company wiki or issue tracker, send a link around and ask people to read and ask questions or, even better, directly edit it if something is not&amp;nbsp;clear.&lt;/p&gt;
&lt;p&gt;Short essays, structured documents such as &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Request_for_Comments"&gt;RFCs&lt;/a&gt; or &lt;a class="reference external" href="https://www.python.org/dev/peps/"&gt;PEPs&lt;/a&gt; are great to convey a proposal or an idea.  These documents can be distributed, discussed and enhanced over email and no boring meetings are required.  They don&amp;#8217;t have to be super formal to be useful: the time spent on just gathering the words together helps to get out something solid out of the thinking&amp;nbsp;process.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="be-responsive"&gt;
&lt;h2&gt;Be&amp;nbsp;responsive&lt;/h2&gt;
&lt;p&gt;Asynchronous communication as mentioned before does not work without trust.  People will bother you on the phone (or through other synchronous channels) if they fear that you won&amp;#8217;t take the time to read your e-mails or review the documents you received.  Trust can be build by being &lt;em&gt;responsive&lt;/em&gt;.  If people develop trust in me and learn that they will get a response from me in time, it helps them to adapt their work flows to&amp;nbsp;mine.&lt;/p&gt;
&lt;p&gt;I try to answer my e-mails in a &amp;#8216;reasonable&amp;#8217; time.  It depends on the context what this&amp;nbsp;means:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;work related mails I try to answer within a&amp;nbsp;day.&lt;/li&gt;
&lt;li&gt;a mail from a friend a subject &amp;#8216;how is it going&amp;#8217; will be answered in a couple of&amp;nbsp;days.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It happens that an email stays unanswered for a longer period of time, but most of the time it&amp;#8217;s because I didn&amp;#8217;t take the time to do it (which effectively means, because I was lazy) not because it was lost or forgotten.  I use the &amp;#8216;Inbox Zero&amp;#8217; strategy (the term coined by Merlin Mann) to handle my mails using a super simple system named &amp;#8216;Trusted Trio&amp;#8217; adopted from &lt;a class="reference external" href="http://lifehacker.com/182318/empty-your-inbox-with-the-trusted-trio"&gt;Lifehacker&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="be-distributed"&gt;
&lt;h2&gt;Be&amp;nbsp;distributed&lt;/h2&gt;
&lt;p&gt;Stuff gets done at physically different locations.  For me these locations are: work, home and when I&amp;#8217;m on the go.  For example, it can happen that in the office during the day I take some notes that I need in the evening at home to complete a certain task.  This means that my notes need to be distributed among all my places of work and they need to be accessible &lt;em&gt;without too much effort&lt;/em&gt;.  In &lt;span class="caps"&gt;GTD&lt;/span&gt; terms: my reference material needs to be accessible from different&amp;nbsp;contexts.&lt;/p&gt;
&lt;p&gt;More&amp;nbsp;specifically:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;It&amp;#8217;s a commonplace, but I can access my e-mails from&amp;nbsp;anywhere.&lt;/li&gt;
&lt;li&gt;I synchronize my browser bookmarks and history using Firefox, so I can save interesting sites for reading them later, somewhere&amp;nbsp;else.&lt;/li&gt;
&lt;li&gt;My configuration files are stored &lt;a class="reference external" href="https://github.com/wagdav/rcfiles"&gt;on GitHub&lt;/a&gt; so I can access them from all my work&amp;nbsp;stations.&lt;/li&gt;
&lt;li&gt;My notes are in a text file in a Dropbox&amp;nbsp;folder.&lt;/li&gt;
&lt;li&gt;My task list is kept in sync by &lt;a class="reference external" href="https://taskwarrior.org"&gt;Taskwarrior&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#8217;d like to improve on my current setup to make my personal data, such as pictures, documents, etc. more accessible when I&amp;#8217;m not home (only for myself in a secure manner
of course).  Maybe I write a post about this some other&amp;nbsp;time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="summary"&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;I try to shape my working habits to get my stuff done in the most efficient manner.  I identified four principles (no distractions, asynchronous communication, responsiveness and distribution) which can help me to achieve&amp;nbsp;this.&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"/><category term="gtd"/></entry><entry><title>Going mobile</title><link href="https://thewagner.net/blog/2015/08/20/going-mobile/" rel="alternate"/><published>2015-08-20T00:00:00+02:00</published><updated>2015-08-20T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2015-08-20:/blog/2015/08/20/going-mobile/</id><summary type="html">&lt;p class="first last"&gt;This is an experimental post, sort of proof of principle, to see how comfortable it is to write blog posts from my mobile&amp;nbsp;phone.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;This is an experimental post, sort of proof of principle, to see how comfortable it is to write blog posts from my mobile phone.  Maybe I should have called it &lt;a class="reference external" href="https://thewagner.net/blog/2013/03/06/hello-world/"&gt;hello world&lt;/a&gt; from&amp;nbsp;Android.&lt;/p&gt;
&lt;div class="section" id="ingredients"&gt;
&lt;h2&gt;Ingredients&lt;/h2&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;strong&gt;Git based workflow&lt;/strong&gt; I write the posts and &lt;a class="reference external" href="https://thewagner.net/blog/2013/08/09/my-blogging-workflow-with-git/"&gt;generate the blog&lt;/a&gt; on my laptop (using GitHub&amp;nbsp;pages).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Git client on my phone&lt;/strong&gt;. After a bit of research I quickly settled with &lt;a class="reference external" href="http://pocketgit.com"&gt;PocketGit&lt;/a&gt;. It is not for free, but costs only 1.79 &lt;span class="caps"&gt;CHF&lt;/span&gt; and, according to the reviews, this is the best Android client you can&amp;nbsp;get.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An editor&lt;/strong&gt;. Since on the desktop I use vim for everything I gave &lt;a class="reference external" href="https://github.com/momodalo/vimtouch"&gt;Vim Touch&lt;/a&gt; a shot, but was not convinced.  For now I installed the &lt;a class="reference external" href="http://getquoda.com"&gt;Quoda code editor&lt;/a&gt;. So far so good, we will see how I like&amp;nbsp;it.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="setup"&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;p&gt;There was really nothing unusual to do.  Only PocketGit only needed some additional configuration.  I generated an &lt;span class="caps"&gt;SSH&lt;/span&gt; key pair to be used by my phone to access the remote Git repositories.  The rest of the infrastructure was already in&amp;nbsp;place.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusion"&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This first post entirely written on my Android phone is about to finish.  It took me only about an hour to configure everything and I am overall happy with this tool&amp;nbsp;chain.&lt;/p&gt;
&lt;p&gt;Typing on my small phone is a bit painful but I think I can get use to it (otherwise I have to buy a phablet or suchlike).  I will keep publishing the posts only from my laptop where I can comfortably spell check, polish and integrate the changes I made into the master branch. Also my &lt;a class="reference external" href="http://getpelican.com"&gt;blog generator&lt;/a&gt; does not run on Android, but this is not an issue at&amp;nbsp;all.&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"/></entry><entry><title>Code archeology</title><link href="https://thewagner.net/blog/2015/03/25/code-archeology/" rel="alternate"/><published>2015-03-25T00:00:00+01:00</published><updated>2015-03-25T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2015-03-25:/blog/2015/03/25/code-archeology/</id><summary type="html">&lt;p class="first last"&gt;Found some code I wrote back in 2004.  The goal was to control the movement of a telescope, but I ended up fighting with fork and&amp;nbsp;select.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Back in 2004 a friend of mine was building a telescope and I wanted it to have
an automated control system, where the user can select a star she
wants to see and the system would automatically orient the telescope towards the
appropriate celestial coordinates.  I called this ambitious plan: &amp;#8220;Project Starfinder&amp;#8221;.  The plan was that he builds the telescope and I write the software.  We both did our job separately, but we never got around to put our works&amp;nbsp;together.&lt;/p&gt;
&lt;p&gt;Though Project Starfinder failed, the motor controller I built was quite a success.  The other day I was browsing through my old backups and I stumbled upon the code I wrote 11 years ago.  &lt;tt class="docutils literal"&gt;motorc&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;motord&lt;/tt&gt; were the client and the server component, respectively, of my stepper motor&amp;nbsp;controller.&lt;/p&gt;
&lt;div class="section" id="daemon"&gt;
&lt;h2&gt;Daemon&lt;/h2&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;motord&lt;/tt&gt; daemon was responsible to receive messages from the connected clients and translate them to instructions to be written to the parallel port.  I also built a circuit that could drive four motors connected to the PCs parallel port.  The daemon needed to run with root&amp;nbsp;privileges.&lt;/p&gt;
&lt;p&gt;The daemon was accepting connections on a PF_LOCAL socket.  For each incoming connection the daemon forked off a child process to handle the one to one communication with the connected client.  I had read somewhere that Apache worked this way and I remember being quiet very to learn about &lt;tt class="docutils literal"&gt;fork()&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;I used &lt;tt class="docutils literal"&gt;select&lt;/tt&gt; on an &lt;tt class="docutils literal"&gt;fd_set&lt;/tt&gt; to process the incoming messages.  This caused me a lot of headaches.  I didn&amp;#8217;t really understand what was going on with these file descriptors.  Everything about them seemed magical.  I probably copied the respective code from a tutorial or&amp;nbsp;somewhere.&lt;/p&gt;
&lt;p&gt;Anyhow, the messages arrived from the socket and they were processed in a large&amp;nbsp;switch-case:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fork&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* forking off */&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* if we are a child process */&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FD_SETSIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t_motor_command&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;syslog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LOG_DAEMON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LOG_DEBUG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Instruction: 0x%x, Address: 0x%x&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BYE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* TODO: a safer solution needed */&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;MOTOREN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Motor enable */&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;motors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;MOTORDIS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Motor disable */&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;motors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;MOTORR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Direction right */&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;motors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;MOTORL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Direction left */&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;motors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;MOTORCLR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="cm"&gt;/* clear the position */&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="n"&gt;motors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is the code from the source file almost literally.  I used 8 spaces for indentation and apparently I didn&amp;#8217;t care about lines longer than 80 characters back&amp;nbsp;then.&lt;/p&gt;
&lt;p&gt;I developed a simple binary protocol to communicate over the socket.  The commands were represented by &lt;tt class="docutils literal"&gt;t_motor_command&lt;/tt&gt; data&amp;nbsp;structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;WORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="cm"&gt;/* instruction byte*/&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;WORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="cm"&gt;/* motor address   */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t_motor_command&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pretty standard&amp;nbsp;stuff.&lt;/p&gt;
&lt;p&gt;The motor daemon also had the following&amp;nbsp;features:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;read and parsed a configuration&amp;nbsp;file&lt;/li&gt;
&lt;li&gt;supported arbitrary numbers of motors. In fact the motor objects were stored in a linked&amp;nbsp;list.&lt;/li&gt;
&lt;li&gt;wrote log messages to the&amp;nbsp;syslog&lt;/li&gt;
&lt;li&gt;changes in the motor position were made available to all&amp;nbsp;clients&lt;/li&gt;
&lt;li&gt;handled &lt;span class="caps"&gt;SIGTERM&lt;/span&gt; and &lt;span class="caps"&gt;SIGCHILD&lt;/span&gt; signals and made a clean&amp;nbsp;exit&lt;/li&gt;
&lt;li&gt;it was &lt;span class="caps"&gt;GPL&lt;/span&gt;&amp;nbsp;licensed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I didn&amp;#8217;t know how to use &lt;tt class="docutils literal"&gt;valgrind&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;gdb&lt;/tt&gt; back then, so probably it leaked memory&amp;nbsp;:-).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="graphical-client"&gt;
&lt;h2&gt;Graphical&amp;nbsp;client&lt;/h2&gt;
&lt;p&gt;My memories about development of the client application are more vague: it was much faster to develop it, and also it is much simpler program than the daemon.  I used Glade to design a &lt;span class="caps"&gt;GTK&lt;/span&gt; interface (with &lt;span class="caps"&gt;GTK&lt;/span&gt; 1.2).  I tried to compile the project in order to make some screenshots of the interface, but I failed.  The project depends on old libraries, moreover the newer version of Glade is having troubles reading the old interface&amp;nbsp;files.&lt;/p&gt;
&lt;p&gt;Anyway the interface was quite simple: it had four knobs for the four motors.  As the user turned the knobs the motors turned.  Very exciting!  If you opened multiple clients the knobs were synchronized (there was no position feedback from the&amp;nbsp;motors).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="summary"&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Reading through the code brought back some nice memories about this project.  I had great fun designing the client-server architecture and I was really proud that I could handle multiple clients by forking off the server process.  It&amp;#8217;s a pity though that the code didn&amp;#8217;t move any&amp;nbsp;telescopes&amp;#8230;&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"/></entry><entry><title>The ultimate eclipsometer™</title><link href="https://thewagner.net/blog/2015/03/20/the-ultimate-eclipsometertm/" rel="alternate"/><published>2015-03-20T00:00:00+01:00</published><updated>2015-03-20T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2015-03-20:/blog/2015/03/20/the-ultimate-eclipsometertm/</id><summary type="html">&lt;p class="first last"&gt;Building an obscura camera out of cardboard in the&amp;nbsp;office.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;On the day of the &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Solar_eclipse_of_March_20,_2015"&gt;solar eclipse&lt;/a&gt; I improvized a &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Camera_obscura"&gt;camera obscura&lt;/a&gt; in the office.  It&amp;#8217;s not nice, but functional and took only 10 minutes to make it.  It was great fun to see my colleagues tucking their heads in the box to see the&amp;nbsp;phenomenon.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;a class="reference external image-reference" href="https://thewagner.net/images/eclipse-1.jpg"&gt;
&lt;img alt="Box outside" src="https://thewagner.net/images/eclipse-1.jpg" style="width: 100%;" /&gt;
&lt;/a&gt;
&lt;p class="caption"&gt;I got a cardboard box from the store.  I used a piece of plastic (cut out
from a 3.5&amp;#8221; floppy disk) to create a thin slit.  The slit is fixed over a
hole I cut in the side of the cardboard.  An office chair provides the&amp;nbsp;support.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="figure"&gt;
&lt;a class="reference external image-reference" href="https://thewagner.net/images/eclipse-2.jpg"&gt;
&lt;img alt="Box inside" src="https://thewagner.net/images/eclipse-2.jpg" style="width: 100%;" /&gt;
&lt;/a&gt;
&lt;p class="caption"&gt;I glued a white sheet of paper in the box, on the side that is opposite to
the slit.  The image of the eclipse is small, but surprisingly&amp;nbsp;sharp.&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"/></entry><entry><title>My blogging workflow with git</title><link href="https://thewagner.net/blog/2013/08/09/my-blogging-workflow-with-git/" rel="alternate"/><published>2013-08-09T00:00:00+02:00</published><updated>2013-08-09T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2013-08-09:/blog/2013/08/09/my-blogging-workflow-with-git/</id><summary type="html">&lt;p class="first last"&gt;Create a topical branch and make commits in that.  When ready, rebase the topical branch on master and merge.&amp;nbsp;Publish.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;This is a description of my &lt;a class="reference external" href="http://git-scm.org"&gt;git&lt;/a&gt; workflow for writing blog posts.  I will use this very post as an example and explain in detail how it was&amp;nbsp;made.&lt;/p&gt;
&lt;div class="section" id="start-a-new-topical-branch"&gt;
&lt;h2&gt;Start a new topical&amp;nbsp;branch&lt;/h2&gt;
&lt;p&gt;I create a topical branch named &lt;tt class="docutils literal"&gt;workflow&lt;/tt&gt; (because I&amp;#8217;m working on a post about my workflow) from the &lt;tt class="docutils literal"&gt;master&lt;/tt&gt; branch&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;checkout&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;workflow
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I edit the file &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;content/2013-08-09-Git-workflow.rst&lt;/span&gt;&lt;/tt&gt; and start writing the post.  When I have enough typing for the day I commit the&amp;nbsp;changes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;content/tech/2013-08-09-Git-workflow.rst
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Add post: Git workflow.&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It rarely happens that I finish a post in one go.  When I feel like writing more I make some modifications (still on the &lt;tt class="docutils literal"&gt;workflow&lt;/tt&gt; branch) and commit&amp;nbsp;them:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Continue workflow post.&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It typically takes two or three iterations, adding parts, fixing typos, etc. until the post is finished.  In the end the topical branch contains quite a few commits since it was forked off from &lt;tt class="docutils literal"&gt;master&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;log&lt;span class="w"&gt; &lt;/span&gt;master..
&lt;span class="o"&gt;[&lt;/span&gt;there&lt;span class="w"&gt; &lt;/span&gt;may&lt;span class="w"&gt; &lt;/span&gt;be&lt;span class="w"&gt; &lt;/span&gt;some&lt;span class="w"&gt; &lt;/span&gt;more&lt;span class="w"&gt; &lt;/span&gt;commits&lt;span class="w"&gt; &lt;/span&gt;here&lt;span class="o"&gt;]&lt;/span&gt;

commit&lt;span class="w"&gt; &lt;/span&gt;4f721af41b2c0d52a8456bb6735ad0f56754ea98
Author:&lt;span class="w"&gt; &lt;/span&gt;David&lt;span class="w"&gt; &lt;/span&gt;Wagner
Date:&lt;span class="w"&gt;   &lt;/span&gt;Fri&lt;span class="w"&gt; &lt;/span&gt;Aug&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;:44:58&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2013&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200

&lt;span class="w"&gt;    &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;log&lt;span class="w"&gt; &lt;/span&gt;output.

commit&lt;span class="w"&gt; &lt;/span&gt;f77de095d0d5225a566782c52133be7f65166016
Author:&lt;span class="w"&gt; &lt;/span&gt;David&lt;span class="w"&gt; &lt;/span&gt;Wagner
Date:&lt;span class="w"&gt;   &lt;/span&gt;Fri&lt;span class="w"&gt; &lt;/span&gt;Aug&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;:44:30&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2013&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200

&lt;span class="w"&gt;    &lt;/span&gt;Add&lt;span class="w"&gt; &lt;/span&gt;summary.

commit&lt;span class="w"&gt; &lt;/span&gt;e332a4b53c8cdd94f3117a949a99367b56a8bc6e
Author:&lt;span class="w"&gt; &lt;/span&gt;David&lt;span class="w"&gt; &lt;/span&gt;Wagner
Date:&lt;span class="w"&gt;   &lt;/span&gt;Fri&lt;span class="w"&gt; &lt;/span&gt;Aug&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;:39:38&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2013&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200

&lt;span class="w"&gt;    &lt;/span&gt;Add&lt;span class="w"&gt; &lt;/span&gt;post:&lt;span class="w"&gt; &lt;/span&gt;Git&lt;span class="w"&gt; &lt;/span&gt;workflow.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="rebase-on-master-and-squash-commits"&gt;
&lt;h2&gt;Rebase on master and squash&amp;nbsp;commits&lt;/h2&gt;
&lt;p&gt;I want to &amp;#8220;compress&amp;#8221; all these into one single commit, since there&amp;#8217;s no point having commits in the &lt;tt class="docutils literal"&gt;master&lt;/tt&gt; branch with messages such as &amp;#8220;Add summary&amp;#8221;, &amp;#8220;Fix typo.&amp;#8221;, &amp;#8220;Continue this and that.&amp;#8221;.  In git&amp;#8217;s words this is called interactive&amp;nbsp;rebasing.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;rebase&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;master
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This pops up &lt;tt class="docutils literal"&gt;$&lt;span class="caps"&gt;EDITOR&lt;/span&gt;&lt;/tt&gt; with a file to edit the rebase&amp;nbsp;plan:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pick&lt;span class="w"&gt; &lt;/span&gt;e332a4b&lt;span class="w"&gt; &lt;/span&gt;Add&lt;span class="w"&gt; &lt;/span&gt;post:&lt;span class="w"&gt; &lt;/span&gt;Git&lt;span class="w"&gt; &lt;/span&gt;workflow.
pick&lt;span class="w"&gt; &lt;/span&gt;f77de09&lt;span class="w"&gt; &lt;/span&gt;Add&lt;span class="w"&gt; &lt;/span&gt;summary.
pick&lt;span class="w"&gt; &lt;/span&gt;4f721af&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;log&lt;span class="w"&gt; &lt;/span&gt;output.

&lt;span class="c1"&gt;# Rebase 6ed71cf..9be73d2 onto 6ed71cf&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# Commands:&lt;/span&gt;
&lt;span class="c1"&gt;#  p, pick = use commit&lt;/span&gt;
&lt;span class="c1"&gt;#  r, reword = use commit, but edit the commit message&lt;/span&gt;
&lt;span class="c1"&gt;#  e, edit = use commit, but stop for amending&lt;/span&gt;
&lt;span class="c1"&gt;#  s, squash = use commit, but meld into previous commit&lt;/span&gt;
&lt;span class="c1"&gt;#  f, fixup = like &amp;quot;squash&amp;quot;, but discard this commit&amp;#39;s log message&lt;/span&gt;
&lt;span class="c1"&gt;#  x, exec = run command (the rest of the line) using shell&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# These lines can be re-ordered; they are executed from top to bottom.&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# If you remove a line here THAT COMMIT WILL BE LOST.&lt;/span&gt;
&lt;span class="c1"&gt;# However, if you remove everything, the rebase will be aborted.&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The comments explain very clearly what I need to do: I modify the file to contain the following (omitting the&amp;nbsp;comments):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
pick e332a4b Add post: Git workflow.
squash f77de09 Add summary.
squash 4f721af git log output.
&lt;/pre&gt;
&lt;p&gt;When the file is saved, I exit from the editor.  Git starts the rebase offering to edit the commit message for each posts to remain, then finally&amp;nbsp;reporting:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
[...]
Successfully rebased and updated refs/heads/workflow.
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="merge-into-master-and-publish"&gt;
&lt;h2&gt;Merge into master and&amp;nbsp;publish&lt;/h2&gt;
&lt;p&gt;Now I switch back to &lt;tt class="docutils literal"&gt;master&lt;/tt&gt; and merge, then delete the topical&amp;nbsp;branch:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;checkout&lt;span class="w"&gt; &lt;/span&gt;master
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;merge&lt;span class="w"&gt; &lt;/span&gt;workflow
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;workflow
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The new post is ready, the blog can be regenerated and&amp;nbsp;published.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="summary"&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;In short, I&amp;#8217;m quite pleased with this setup.  Using the combination of git and the &lt;a class="reference external" href="http://docs.getpelican.com"&gt;Pelican&lt;/a&gt; static blog generator is really easy and has a lot of advantages: I can work on multiple posts at the same time, even offline and publishing is just a matter of a &lt;tt class="docutils literal"&gt;git push&lt;/tt&gt;.  The above workflow rose naturally, when I became to know enough about git&amp;#8217;s branches and&amp;nbsp;rebasing.&lt;/p&gt;
&lt;p&gt;Evidently this whole thing may appear way more complicated than necessary for the faint hearted on Blogger, however this branch juggling turns out to be quite powerful when it&amp;#8217;s about software development in the wild where clean commits and keeping track of changes you make on the codebase are&amp;nbsp;essential.&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"/></entry><entry><title>Total control</title><link href="https://thewagner.net/blog/2013/07/22/total-control/" rel="alternate"/><published>2013-07-22T00:00:00+02:00</published><updated>2013-07-22T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2013-07-22:/blog/2013/07/22/total-control/</id><summary type="html">&lt;p class="first last"&gt;I ordered some electronic components to control my unipolar stepper
motor and read data from a 10k&amp;nbsp;potentiometer.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I ordered some electronic components from &lt;a class="reference external" href="http://play-zone.ch"&gt;Play-Zone&lt;/a&gt; which made me really easy to control my unipolar stepper motor and read data from a 10k&amp;nbsp;potentiometer.&lt;/p&gt;
&lt;div class="section" id="stepper-motor"&gt;
&lt;h2&gt;Stepper&amp;nbsp;motor&lt;/h2&gt;
&lt;p&gt;After sufficient &lt;a class="reference external" href="https://thewagner.net/blog/2013/07/19/prototypes-for-stepper-motor-control/"&gt;preparation&lt;/a&gt;, it took me less than 15 minutes to have a nicely purring and turning stepper motor on the breadboard.  The key element, a &lt;span class="caps"&gt;ULN2803A&lt;/span&gt; containing 8 Darlington Arrays, takes care of&amp;nbsp;everything.&lt;/p&gt;
&lt;img alt="Stepper motor schema" src="https://thewagner.net/images/pi/stepper_prototype_3_schem.png" /&gt;
&lt;/div&gt;
&lt;div class="section" id="potentiometer"&gt;
&lt;h2&gt;Potentiometer&lt;/h2&gt;
&lt;p&gt;Not strictly related, but in the same go I used the newly arrived &lt;span class="caps"&gt;MCP3002&lt;/span&gt; &lt;span class="caps"&gt;ADC&lt;/span&gt; to read the position of a 10k potentiometer.  I borrowed some code from the &lt;a class="reference external" href="http://learn.adafruit.com/reading-a-analog-in-and-controlling-audio-volume-with-the-raspberry-pi/overview"&gt;Adafruit website&lt;/a&gt; with some modifications from &lt;a class="reference external" href="http://dmt195.wordpress.com/2012/09/26/mcp3002-example-code-for-raspberry-pi-adc-through-spi/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;img alt="Potentiometer schema" src="https://thewagner.net/images/pi/potentiometer_schem.png" /&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;RPi.GPIO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;GPIO&lt;/span&gt;

&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setmode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BOARD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# read SPI data from MCP3002 chip, 2 possible adc&amp;#39;s (0 thru 1)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;readadc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;adcnum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clockpin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mosipin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;misopin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cspin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;adcnum&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;adcnum&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cspin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clockpin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# start clock low&lt;/span&gt;
        &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cspin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# bring CS low&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;adcnum&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;commandout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x6&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;commandout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x7&lt;/span&gt;
        &lt;span class="n"&gt;commandout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;    &lt;span class="c1"&gt;# we only need to send 3 bits here&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commandout&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                        &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mosipin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mosipin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;commandout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
                &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clockpin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clockpin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;adcout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="c1"&gt;# read in one empty bit, one null bit and 10 ADC bits&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clockpin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clockpin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;adcout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;misopin&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
                        &lt;span class="n"&gt;adcout&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="mh"&gt;0x1&lt;/span&gt;

        &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cspin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;adcout&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;       &lt;span class="c1"&gt;# first bit is &amp;#39;null&amp;#39; so drop it&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;adcout&lt;/span&gt;

&lt;span class="n"&gt;SPICS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;
&lt;span class="n"&gt;SPIMOSI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;
&lt;span class="n"&gt;SPIMISO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;
&lt;span class="n"&gt;SPICLK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;

&lt;span class="c1"&gt;# set up the SPI interface pins&lt;/span&gt;
&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SPIMOSI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SPIMISO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SPICLK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SPICS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 10k trim pot connected to adc #0&lt;/span&gt;
&lt;span class="n"&gt;potentiometer_adc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;last_read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;       &lt;span class="c1"&gt;# this keeps track of the last potentiometer value&lt;/span&gt;
&lt;span class="n"&gt;tolerance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;       &lt;span class="c1"&gt;# to keep from being jittery we&amp;#39;ll only change&lt;/span&gt;
                    &lt;span class="c1"&gt;# volume when the pot has moved more than 5 &amp;#39;counts&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# we&amp;#39;ll assume that the pot didn&amp;#39;t move&lt;/span&gt;
        &lt;span class="n"&gt;trim_pot_changed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;

        &lt;span class="c1"&gt;# read the analog pin&lt;/span&gt;
        &lt;span class="n"&gt;trim_pot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readadc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;potentiometer_adc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SPICLK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SPIMOSI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SPIMISO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SPICS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# how much has it changed since the last read?&lt;/span&gt;
        &lt;span class="n"&gt;pot_adjust&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trim_pot&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;last_read&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pot_adjust&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tolerance&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
               &lt;span class="n"&gt;trim_pot_changed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;trim_pot_changed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# convert 10bit adc0 (0-1024) trim pot read into&lt;/span&gt;
                &lt;span class="c1"&gt;# 0-100 volume level&lt;/span&gt;
                &lt;span class="n"&gt;set_volume&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;trim_pot&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;10.24&lt;/span&gt;
                &lt;span class="n"&gt;set_volume&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;set_volume&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# round out decimal value&lt;/span&gt;
                &lt;span class="n"&gt;set_volume&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;set_volume&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# cast volume as integer&lt;/span&gt;

                &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;volume = &lt;/span&gt;&lt;span class="si"&gt;{volume}&lt;/span&gt;&lt;span class="s1"&gt;%&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;volume&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;set_volume&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="c1"&gt;# save the potentiometer reading for the next loop&lt;/span&gt;
                &lt;span class="n"&gt;last_read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;trim_pot&lt;/span&gt;

        &lt;span class="c1"&gt;# hang out and do nothing for a half second&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These two (independent) circuits make a big mess on the breadboard, but it was a lot of fun to wire it up.  Now I can read analog as well as digital inputs from the real world with the Raspberry Pi!&amp;nbsp;Yay!&lt;/p&gt;
&lt;img alt="Potentiometer breadboard" src="https://thewagner.net/images/pi/potentiometer_breadboard.jpg" /&gt;
&lt;/div&gt;
</content><category term="misc"/></entry><entry><title>Prototypes for stepper motor control</title><link href="https://thewagner.net/blog/2013/07/19/prototypes-for-stepper-motor-control/" rel="alternate"/><published>2013-07-19T00:00:00+02:00</published><updated>2013-07-19T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2013-07-19:/blog/2013/07/19/prototypes-for-stepper-motor-control/</id><summary type="html">&lt;p class="first last"&gt;I have a unipolar stepper motor that I want to control with my
Raspberry&amp;nbsp;Pi.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I have a unipolar stepper motor I want to control with my Raspberry Pi.
First I needed to figure out the motor coils&amp;#8217; wiring, then I wrote a small
test script to provide the correct sequence on the &lt;span class="caps"&gt;GPIO&lt;/span&gt;&amp;nbsp;ports.&lt;/p&gt;
&lt;div class="section" id="wiring"&gt;
&lt;h2&gt;Wiring&lt;/h2&gt;
&lt;p&gt;I read about &lt;a class="reference external" href="http://www.stepperworld.com/Tutorials/pgUnipolarTutorial.htm"&gt;stepper motors&lt;/a&gt;, and made the following circuit on the&amp;nbsp;breadboard.&lt;/p&gt;
&lt;img alt="Stepper motor prototype" src="https://thewagner.net/images/pi/stepper_prototype_1.jpg" style="width: 100%;" /&gt;
&lt;p&gt;A 9V battery, an indicator led to show if the power is on, and four
switches.  When a switch is pressed one phase (half coil) is energized.  For
some unknown reason I managed to get the wiring right for the first time, so
pressing the switches one after the other, from top to bottom, made the
motor turn one&amp;nbsp;step.&lt;/p&gt;
&lt;p&gt;The 6 wires of this motor (Japan Servo &lt;span class="caps"&gt;KP68P2&lt;/span&gt;-406, 12V, 33 Ω/phase, 1.8
deg/step) are the&amp;nbsp;following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;2 red (center&amp;nbsp;taps)&lt;/li&gt;
&lt;li&gt;orange (phase&amp;nbsp;1)&lt;/li&gt;
&lt;li&gt;brown (phase&amp;nbsp;2)&lt;/li&gt;
&lt;li&gt;yellow (phase&amp;nbsp;3)&lt;/li&gt;
&lt;li&gt;black (phase&amp;nbsp;4)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="sequence-test"&gt;
&lt;h2&gt;Sequence&amp;nbsp;test&lt;/h2&gt;
&lt;p&gt;I wrote a small test script to output the step sequence on the Pi&amp;#8217;s &lt;span class="caps"&gt;GPIO&lt;/span&gt;
ports.  It has a lot of cool&amp;nbsp;features:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;stepper_seq.py&lt;span class="w"&gt; &lt;/span&gt;-h&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# help&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;stepper_seq.py&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# turns the motor indefinitely, Control-C terminates&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;stepper_seq.py&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;half&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# 4 times the half-step sequence, reversed&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;stepper_seq.py&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;kitt&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# nothing to do with stepper motors ;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the code of &lt;tt class="docutils literal"&gt;stepper_seq.py&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class="c1"&gt;# stepper_seq.py - Stepper motor sequence test&lt;/span&gt;
&lt;span class="c1"&gt;# Copyright (C) 2013 David Wagner&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;itertools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cycle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repeat&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;RPi.GPIO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;GPIO&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;signal&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;

&lt;span class="n"&gt;sequences&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="c1"&gt;# Wave Drive, One-Phase&lt;/span&gt;
             &lt;span class="s1"&gt;&amp;#39;one&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
             &lt;span class="c1"&gt;# Hi-Torque, Two-Phase&lt;/span&gt;
             &lt;span class="s1"&gt;&amp;#39;two&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
             &lt;span class="c1"&gt;# Half-Step&lt;/span&gt;
             &lt;span class="s1"&gt;&amp;#39;half&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;]]}&lt;/span&gt;

&lt;span class="n"&gt;sequences&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;kitt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sequences&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;one&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                           &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sequences&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;one&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])))})&lt;/span&gt;

&lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Stepper motor sequence test.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-p&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;--pins&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metavar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;num&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;GPIO pins to activate (numbering by BOARD)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-s&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;--seq&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;one&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sequences&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
                    &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Coil activation sequence.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-d&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;--delay&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;0.5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Delay in seconds.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-r&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;--reverse&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;store_true&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Reverse direction.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;--num&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Number of complete cycles.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;init_board&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setmode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BOARD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pin&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;init_pins&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pin&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;signal_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Interrupted. Exiting...&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;init_pins&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;ncycles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;Returns the sequence elements n times&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_iterable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pin_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pins&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pins&lt;/span&gt;
    &lt;span class="n"&gt;rep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cycle&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ncycles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sequences&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pin_order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signal_handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;init_board&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;init_pins&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="sequence-test-hardware"&gt;
&lt;h2&gt;Sequence test&amp;nbsp;hardware&lt;/h2&gt;
&lt;p&gt;I put together a circuit to test the script above.  It contains four LEDs,
each connected to one of the Pi&amp;#8217;s &lt;span class="caps"&gt;GPIO&lt;/span&gt; ports through a transistor.  The
&lt;span class="caps"&gt;LED&lt;/span&gt;&amp;#8217;s could be directly connected to the &lt;span class="caps"&gt;IO&lt;/span&gt; ports, but in this project I
wanted to refresh how to use a &lt;a class="reference external" href="http://www.ermicro.com/blog/?p=423"&gt;transistor as a switch&lt;/a&gt; so that the LEDs can be powered from
an external power&amp;nbsp;supply.&lt;/p&gt;
&lt;img alt="Stepper motor prototype schematic" src="https://thewagner.net/images/pi/stepper_prototype_2_schem.png" style="width: 100%;" /&gt;
&lt;p&gt;And on the breadboard it looks like&amp;nbsp;this:&lt;/p&gt;
&lt;img alt="Stepper motor prototype breadboard" src="https://thewagner.net/images/pi/stepper_prototype_2.jpg" style="width: 100%;" /&gt;
&lt;/div&gt;
</content><category term="misc"/></entry><entry><title>Led and button</title><link href="https://thewagner.net/blog/2013/06/26/led-and-button/" rel="alternate"/><published>2013-06-26T00:00:00+02:00</published><updated>2013-06-26T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2013-06-26:/blog/2013/06/26/led-and-button/</id><summary type="html">&lt;p&gt;I finally got around to tinkering with the Raspberry Pi hardware.  A while
ago I&amp;#8217;d ordered a basic electronic kit from ebay with a breadboard and a
bunch of electronic components (resistors, cables, etc) in it.  I started
with a rather elementary project: control of an &lt;span class="caps"&gt;LED&lt;/span&gt; and a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I finally got around to tinkering with the Raspberry Pi hardware.  A while
ago I&amp;#8217;d ordered a basic electronic kit from ebay with a breadboard and a
bunch of electronic components (resistors, cables, etc) in it.  I started
with a rather elementary project: control of an &lt;span class="caps"&gt;LED&lt;/span&gt; and a push-button from
the Pi.  Despite its apparent simplicity it&amp;#8217;s a good opportunity re-learn
some basics: which is the anode/cathode of the &lt;span class="caps"&gt;LED&lt;/span&gt;?  What&amp;#8217;s a
pull-up/pull-down resistor? and so&amp;nbsp;on&amp;#8230;&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s the final&amp;nbsp;&amp;#8216;product&amp;#8217;:&lt;/p&gt;
&lt;img alt="Led and button" src="https://thewagner.net/images/pi/photo_led_button_1.jpg" style="width: 49%;" /&gt;
&lt;img alt="Led and button" src="https://thewagner.net/images/pi/photo_led_button_2.jpg" style="width: 49%;" /&gt;
&lt;p&gt;I needed to cut open up my fancy &lt;a class="reference external" href="https://thewagner.net/blog/2013/03/17/cardboard-raspberry-pi-case/"&gt;cardboard case&lt;/a&gt; :-( to gain access to the
&lt;span class="caps"&gt;GPIO&lt;/span&gt; ports on the Pi.  I may design a new case in the future, one that allows
direct connection to the&amp;nbsp;board.&lt;/p&gt;
&lt;p&gt;I drew the circuit diagram using the &lt;a class="reference external" href="http://www.mbeckler.org/inkscape/circuit_symbols/"&gt;circuit symbol set&lt;/a&gt; for &lt;a class="reference external" href="http://inkscape.org"&gt;Inkscape&lt;/a&gt;.&lt;/p&gt;
&lt;img alt="Led and button schema" src="https://thewagner.net/images/pi/schematic_led_button.png" style="width: 98%;" /&gt;
&lt;p&gt;The drive this wonderful piece of hardware, I wrote the following code that
makes the &lt;span class="caps"&gt;LED&lt;/span&gt; blinking&amp;nbsp;(yaaaay):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# led_blink.py&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;RPi.GPIO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;GPIO&lt;/span&gt;

&lt;span class="c1"&gt;# Set the mode of numbering the pins.&lt;/span&gt;
&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setmode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BOARD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Initialise GPIO10 to high (true) so that the LED is off.&lt;/span&gt;
&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and this program turns the &lt;span class="caps"&gt;LED&lt;/span&gt; on when the button is&amp;nbsp;pressed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# led_button.py&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;RPi.GPIO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;GPIO&lt;/span&gt;

&lt;span class="c1"&gt;# Set the mode of numbering the pins.&lt;/span&gt;
&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setmode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BOARD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Initialise to high (true) so that the LED is off.&lt;/span&gt;
&lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;button_pressed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;button_pressed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Button pressed.&amp;#39;&lt;/span&gt;
                &lt;span class="n"&gt;button_pressed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
        &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;button_pressed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Button released.&amp;#39;&lt;/span&gt;
                &lt;span class="n"&gt;button_pressed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
        &lt;span class="c1"&gt;# When the button switch is not pressed, turn off the LED.&lt;/span&gt;
        &lt;span class="n"&gt;GPIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I took the inspiration and some sample code from the following&amp;nbsp;places:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://visualgdb.com/tutorials/raspberry/LED/"&gt;http://visualgdb.com/tutorials/raspberry/&lt;span class="caps"&gt;LED&lt;/span&gt;/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/turing-machine/two.html"&gt;http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/turing-machine/two.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content><category term="misc"/><category term="raspberrypi"/></entry><entry><title>Fresh theme</title><link href="https://thewagner.net/blog/2013/06/18/fresh-theme/" rel="alternate"/><published>2013-06-18T00:00:00+02:00</published><updated>2013-06-18T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2013-06-18:/blog/2013/06/18/fresh-theme/</id><summary type="html">&lt;p&gt;I changed the blog&amp;#8217;s theme from the default to &lt;a class="reference external" href="https://github.com/jsliang/pelican-fresh/"&gt;fresh&lt;/a&gt;.  I wanted to have
something that uses &lt;a class="reference external" href="http://twitter.github.io/bootstrap/"&gt;Twitter Bootstrap&lt;/a&gt; so that if you resize the browser
window, or read the posts on a small screen, the layout changes&amp;nbsp;dynamically.&lt;/p&gt;
&lt;p&gt;Also, now there&amp;#8217;s a Github ribbon in the top …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I changed the blog&amp;#8217;s theme from the default to &lt;a class="reference external" href="https://github.com/jsliang/pelican-fresh/"&gt;fresh&lt;/a&gt;.  I wanted to have
something that uses &lt;a class="reference external" href="http://twitter.github.io/bootstrap/"&gt;Twitter Bootstrap&lt;/a&gt; so that if you resize the browser
window, or read the posts on a small screen, the layout changes&amp;nbsp;dynamically.&lt;/p&gt;
&lt;p&gt;Also, now there&amp;#8217;s a Github ribbon in the top right corner, and social links
on the&amp;nbsp;right.&lt;/p&gt;
</content><category term="misc"/></entry><entry><title>Backup</title><link href="https://thewagner.net/blog/2013/05/15/backup/" rel="alternate"/><published>2013-05-15T00:00:00+02:00</published><updated>2013-05-15T00:00:00+02:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2013-05-15:/blog/2013/05/15/backup/</id><summary type="html">&lt;p class="first last"&gt;Building a systematic backup solution for my personal laptop at&amp;nbsp;home.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;At work, I stored all my important data on the lab&amp;#8217;s server which
(obviously) was backed up once a day.  At home, on my personal laptop I
haven&amp;#8217;t had a systematic backup solution.  Now I&amp;#8217;m changing&amp;nbsp;this.&lt;/p&gt;
&lt;div class="section" id="everyday-backup-with-obnam"&gt;
&lt;h2&gt;Everyday backup with&amp;nbsp;Obnam&lt;/h2&gt;
&lt;p&gt;I decided that I will backup my laptop&amp;#8217;s important data on my home
file-server.  It&amp;#8217;s a &lt;a class="reference external" href="http://sharecenter.dlink.com/products/DNS-320"&gt;&lt;span class="caps"&gt;DNS&lt;/span&gt;-320 ShareCenter&lt;/a&gt; with 2x1TB disk in &lt;span class="caps"&gt;RAID&lt;/span&gt; 1.
Naturally, this won&amp;#8217;t save me in case of theft or fire in my house, but I
will deal with the off-site backup problem later, when a local backup
problem is&amp;nbsp;solved.&lt;/p&gt;
&lt;p&gt;For my backups I use &lt;a class="reference external" href="http://liw.fi/obnam"&gt;Obnam&lt;/a&gt;.  My configuration file &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;~/.obnam.conf&lt;/span&gt;&lt;/tt&gt; is
qute&amp;nbsp;simple:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
[config]
repository = /media/nas/backup
log = /home/dwagner/.obnam/obnam.log
exclude = /home/dwagner/temp, /home/dwagner/pictures
&lt;/pre&gt;
&lt;p&gt;To backup I&amp;nbsp;run:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ obnam backup $HOME
&lt;/pre&gt;
&lt;p&gt;which takes a couple of minutes.  Occasionally I make obnam forget the old&amp;nbsp;files:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ obnam forget --keep=14d
&lt;/pre&gt;
&lt;p&gt;Of course I could put this in a little script and use &lt;tt class="docutils literal"&gt;cron&lt;/tt&gt; or something
to run the backup regularly, but I do it manually for a while to gain some&amp;nbsp;experience.&lt;/p&gt;
&lt;p&gt;I exclude the temporary files in my home directory because it just contains
all kinds of junk I don&amp;#8217;t really care loosing.  I also don&amp;#8217;t backup this way
the &lt;tt class="docutils literal"&gt;pictures&lt;/tt&gt; directory, since I secure my photos in there&amp;nbsp;differently.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="photo-backup-with-git-annex"&gt;
&lt;h2&gt;Photo backup with&amp;nbsp;git-annex&lt;/h2&gt;
&lt;p&gt;I store my personal photo collection in a &lt;a class="reference external" href="http://git-annex.branchable.com"&gt;git-annex&lt;/a&gt; repository.  I have
at least two copies of all the pictures (one on the file server and one on a
&lt;span class="caps"&gt;USB&lt;/span&gt; &lt;span class="caps"&gt;HDD&lt;/span&gt; dedicated for this purpose).  A copy of the recent photos, usually
the current year&amp;#8217;s are on my laptop as well.  I noticed that these are the
pictures I access the most frequently, mainly showing them to friends and
family.  If I need to go back earlier in time, I can have those photos from
home in a day (or when I go home), but not instantly from my laptop.  This
works for me, because the &lt;span class="caps"&gt;SSD&lt;/span&gt; on my laptop is not that spacious, and I don&amp;#8217;t
want to store all my photos on&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;When I download new pictures from my camera I do &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;git-annex&lt;/span&gt; sync&lt;/tt&gt; across
the picture repositories making sure that my precious memories are well&amp;nbsp;preserved.&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"/></entry><entry><title>Cardboard Raspberry Pi case</title><link href="https://thewagner.net/blog/2013/03/17/cardboard-raspberry-pi-case/" rel="alternate"/><published>2013-03-17T00:00:00+01:00</published><updated>2013-03-17T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2013-03-17:/blog/2013/03/17/cardboard-raspberry-pi-case/</id><summary type="html">&lt;p&gt;I bought a &lt;a class="reference external" href="http://raspberrypi.org"&gt;Raspberry Pi&lt;/a&gt;.  No need to explain
this since nowadays &lt;em&gt;everybody&lt;/em&gt; buys a Raspberry Pi.  Even if I don&amp;#8217;t use it,
large part of its (not too high) price goes for charity, I&amp;nbsp;figured.&lt;/p&gt;
&lt;p&gt;I was reluctant to buy a casing for it in the shop, because …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I bought a &lt;a class="reference external" href="http://raspberrypi.org"&gt;Raspberry Pi&lt;/a&gt;.  No need to explain
this since nowadays &lt;em&gt;everybody&lt;/em&gt; buys a Raspberry Pi.  Even if I don&amp;#8217;t use it,
large part of its (not too high) price goes for charity, I&amp;nbsp;figured.&lt;/p&gt;
&lt;p&gt;I was reluctant to buy a casing for it in the shop, because I wanted to
build it myself.  There are tons of interesting RPi case projects out there,
but I found &lt;a class="reference external" href="http://www.judepullen.com/designmodelling/raspberry-pi-case/"&gt;Jude Pullen&lt;/a&gt;&amp;#8216;s the most
interesting.  I followed his instructions and the result is a very cool
Raspberry Pi case out of cardboard.  In fact, I recycled the packaging of my
new&amp;nbsp;ThinkPad.&lt;/p&gt;
&lt;img alt="Cardboard case" class="align-center" src="https://thewagner.net/images/rpi-cardboard.jpg" style="width: 100%;" /&gt;
&lt;p&gt;I didn&amp;#8217;t do the light-pipes.  I&amp;#8217;m not sure if this is the Pi&amp;#8217;s final casing
and I didn&amp;#8217;t want to glue anything onto the board itself.  In summary,
working with cardboard is easy, fun and kept me away from the computer for
some nights.  I may build a better version (with light pipes), or even
something completely different in the&amp;nbsp;future.&lt;/p&gt;
</content><category term="tech"/><category term="raspberrypi"/></entry><entry><title>Brain transplant</title><link href="https://thewagner.net/blog/2013/03/12/brain-transplant/" rel="alternate"/><published>2013-03-12T00:00:00+01:00</published><updated>2013-03-12T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2013-03-12:/blog/2013/03/12/brain-transplant/</id><summary type="html">&lt;p&gt;In the lab we have a camera system composed of four cameras.  The system is
controlled by two identical PCs, two cameras connected to each.  After a
long break of operation, when we wanted to use the system again, the hard
drive in one &lt;span class="caps"&gt;PC&lt;/span&gt; decided to quit science and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In the lab we have a camera system composed of four cameras.  The system is
controlled by two identical PCs, two cameras connected to each.  After a
long break of operation, when we wanted to use the system again, the hard
drive in one &lt;span class="caps"&gt;PC&lt;/span&gt; decided to quit science and went dead.  We replaced the poor
fellow with a new drive and I wanted to transfer the system as it is from
the &lt;tt class="docutils literal"&gt;healty&lt;/tt&gt; computer to the new drive of the &lt;tt class="docutils literal"&gt;braindead&lt;/tt&gt; system .
Following the brain transplant procedure in its most realistic, bloody&amp;nbsp;purity.&lt;/p&gt;
&lt;p&gt;My idea is to run on &lt;tt class="docutils literal"&gt;healthy&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
dd if=/dev/hda | ssh user&amp;#64;braindead sudo dd of=/dev/sda
&lt;/pre&gt;
&lt;p&gt;To this end I boot up &lt;tt class="docutils literal"&gt;braindead&lt;/tt&gt; (with the new drive in) from a &lt;a class="reference external" href="http://www.debian.org/CD/live/"&gt;Debian
Live &lt;span class="caps"&gt;CD&lt;/span&gt;&lt;/a&gt;.  While setting up the network
(&lt;span class="caps"&gt;IP&lt;/span&gt; address, &lt;span class="caps"&gt;DNS&lt;/span&gt;, etc.), it turns out that the network card needs some
non-free firmware which are not on the Installer/Live &lt;span class="caps"&gt;CD&lt;/span&gt;.  This is a bit
annoying but not the end of the world.  After some googling I learn that I
need &lt;a class="reference external" href="http://packages.debian.org/squeeze/all/firmware-linux-nonfree/download"&gt;fimrware-linux-nonfree&lt;/a&gt;,
so I download and put it on a &lt;span class="caps"&gt;USB&lt;/span&gt; stick and install (&lt;tt class="docutils literal"&gt;dpkg &lt;span class="pre"&gt;-i&lt;/span&gt;&lt;/tt&gt;) it on
&lt;tt class="docutils literal"&gt;braindead&lt;/tt&gt;.  Now it has network connection and an &lt;span class="caps"&gt;SSH&lt;/span&gt; server&amp;nbsp;running.&lt;/p&gt;
&lt;p&gt;To prepare for the transplant I put &lt;tt class="docutils literal"&gt;healthy&lt;/tt&gt; in single user mode and
mount the file system read-only (as&amp;nbsp;root):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ init 1
$ mount / -o remount,ro
&lt;/pre&gt;
&lt;p&gt;Now everything is ready for the procedure.  I run &lt;tt class="docutils literal"&gt;dd&lt;/tt&gt; through &lt;span class="caps"&gt;SSH&lt;/span&gt; as
described above.  It takes some time, but the transfer works&amp;nbsp;fine.&lt;/p&gt;
&lt;p&gt;On &lt;tt class="docutils literal"&gt;braindead&lt;/tt&gt;, still running the Live &lt;span class="caps"&gt;CD&lt;/span&gt;,  I mount the new disk&amp;nbsp;and&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;change the host name in &lt;tt class="docutils literal"&gt;/etc/hostname&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;generate new host keys
(&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ssh-keygen&lt;/span&gt; &lt;span class="pre"&gt;-t&lt;/span&gt; rsa &lt;span class="pre"&gt;-f&lt;/span&gt; /etc/ssh/ssh_host_rsa_key&lt;/tt&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I reboot &lt;tt class="docutils literal"&gt;braindead&lt;/tt&gt; and voilá, it works!  Well almost&amp;#8230; I experience
some problem with the networking.  I quickly figure it out that the network
card enumeration (eth0 eth1 swap thingy) is screwed, but it is easy to fix
by editing &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/etc/udev/rules.d/70-persistent-net.rules&lt;/span&gt;&lt;/tt&gt; and removing the
lines that refer (by &lt;span class="caps"&gt;MAC&lt;/span&gt; address) to the network card which is in the other&amp;nbsp;machine.&lt;/p&gt;
</content><category term="tech"/></entry><entry><title>Pelican up and running</title><link href="https://thewagner.net/blog/2013/03/08/pelican-up-and-running/" rel="alternate"/><published>2013-03-08T00:00:00+01:00</published><updated>2013-03-08T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2013-03-08:/blog/2013/03/08/pelican-up-and-running/</id><summary type="html">&lt;p&gt;I decided to start blogging again.  I wanted to move away from &lt;a class="reference external" href="http://www.blogspot.com"&gt;Blogspot&lt;/a&gt; and write posts using some markup in &lt;tt class="docutils literal"&gt;vi&lt;/tt&gt; and
publish them as static &lt;span class="caps"&gt;HTML&lt;/span&gt;.  I looked into many static blog generators and
I ended up choosing &lt;a class="reference external" href="http://getpelican.com"&gt;Pelican&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The steps in the documentation worked fine, I had my …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I decided to start blogging again.  I wanted to move away from &lt;a class="reference external" href="http://www.blogspot.com"&gt;Blogspot&lt;/a&gt; and write posts using some markup in &lt;tt class="docutils literal"&gt;vi&lt;/tt&gt; and
publish them as static &lt;span class="caps"&gt;HTML&lt;/span&gt;.  I looked into many static blog generators and
I ended up choosing &lt;a class="reference external" href="http://getpelican.com"&gt;Pelican&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The steps in the documentation worked fine, I had my blog running in about
2 mins.  I decided to separate the site generation in two different&amp;nbsp;repositories&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/wagdav/thewagner.net"&gt;https://github.com/wagdav/thewagner.net&lt;/a&gt; contains the posts in &lt;span class="caps"&gt;RST&lt;/span&gt; files
and the neccessary config files for&amp;nbsp;Pelican.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/wagdav/wagdav.github.com"&gt;https://github.com/wagdav/wagdav.github.com&lt;/a&gt; contains the actual &lt;span class="caps"&gt;HTML&lt;/span&gt;
source and receieves only automatic updates from the first repository.
This is set up to generate a &lt;a class="reference external" href="http://pages.github.com/"&gt;User Github Page&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On my laptop I have the clone of these two repositories&amp;nbsp;as:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
~/blog/thewagner.net/
~/blog/wagdav.github.com/
&lt;/pre&gt;
&lt;p&gt;I configured Pelican to place its output in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;../wagdav.github.com&lt;/span&gt;&lt;/tt&gt;.  I
needed to make a small adjustment in the generated &lt;tt class="docutils literal"&gt;Makefile&lt;/tt&gt;, to prevent
the &lt;tt class="docutils literal"&gt;make clean&lt;/tt&gt; command destroying the git repository in the output
directory and deleting the files needed for Github Pages.  So now the
&lt;tt class="docutils literal"&gt;clean&lt;/tt&gt; target&amp;nbsp;is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nf"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;@find&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;OUTPUTDIR&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-mindepth&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-not&lt;span class="w"&gt; &lt;/span&gt;-iwholename&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;*/.git*&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;-not&lt;span class="w"&gt; &lt;/span&gt;-name&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;README.md&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;-not&lt;span class="w"&gt; &lt;/span&gt;-name&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;CNAME&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which does the job just&amp;nbsp;fine.&lt;/p&gt;
&lt;p&gt;The next steps are to import posts from my &lt;a class="reference external" href="http://aventuresalausanne.blogspot.com"&gt;old blog&lt;/a&gt; and change the default style.  I
want to have something that uses &lt;a class="reference external" href="https://getbootstrap.com"&gt;Twitter Bootstrap&lt;/a&gt;.&lt;/p&gt;
</content><category term="tech"/><category term="pelican"/></entry><entry><title>Hello world</title><link href="https://thewagner.net/blog/2013/03/06/hello-world/" rel="alternate"/><published>2013-03-06T00:00:00+01:00</published><updated>2013-03-06T00:00:00+01:00</updated><author><name>David Wagner</name></author><id>tag:thewagner.net,2013-03-06:/blog/2013/03/06/hello-world/</id><content type="html">&lt;p&gt;This is the first&amp;nbsp;post.&lt;/p&gt;
</content><category term="misc"/><category term="test"/></entry></feed>