<?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 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;AWS …&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 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;AWS 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 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
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'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; 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;NATS&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'll have an opportunity to integrate them into future
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's &lt;em&gt;Hail Mary
Project&lt;/em&gt;. To finish the year, I spent my Christmas reading Bertrand Meyer's
&lt;em&gt;Agile!&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading my blog and happy 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 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't mind that this year ends 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'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 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't
use this language professionally, I look forward to coding in Clojure every
December.  Usually, I solved the day's problem before leaving to work, though
sometimes I polished my code in the 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'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's clumsy 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's title the word "normal" means &lt;em&gt;systemic&lt;/em&gt;, accidents that involve the
unanticipated interaction of many failures.  Perrow …&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's title the word "normal" 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 accidents.&lt;/p&gt;
&lt;h1&gt;No easy 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 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
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
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 world.&lt;/p&gt;
&lt;p&gt;Instead of blaming a single component or a person, Perrow develops his DEPOSE
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 fails.&lt;/p&gt;
&lt;h1&gt;System, subsystem, units and 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 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
"common-mode unit".  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 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 components.&lt;/p&gt;
&lt;h1&gt;Interaction and 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
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'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't receive new pieces anymore.
Furthermore, a failure on one assembly line typically doesn't affect
neighbouring lines, at least not 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't have possibly made better decisions during the accident because of the
inherent complexity of a nuclear 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 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's definition, this makes a junior college more tightly
coupled than a university.  A university doesn'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 college.&lt;/p&gt;
&lt;h1&gt;Fixing complex, tightly coupled systems&lt;/h1&gt;
&lt;p&gt;According to Perrow'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 them.&lt;/p&gt;
&lt;p&gt;If we cannot change a complex, tightly coupled technology — and we don't want
to abandon it —, perhaps we could prepare ourselves better to face unforeseen
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 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
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 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's afterword contains a few extra references to
books and papers that further developed Perrow'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;Y2K&lt;/a&gt; problem didn't induce an apocalypse, but we
definitely saw defective software causing 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 environment.&lt;/p&gt;
&lt;h1&gt;Acknowledgement&lt;/h1&gt;
&lt;p&gt;Thanks Rafał for suggesting and lending me this 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'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's explanations with a …&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'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'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 notes.&lt;/p&gt;
&lt;p&gt;I view this in-class note-taking as a one-step process: I capture the teacher's
words on paper and the notes become directly usable for 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 usable.&lt;/p&gt;
&lt;p&gt;When I read a technical text, I take notes.  I don'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' page and form a complete
sentence about the concept or 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 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
  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 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 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 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's see each step in 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 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't follow any particular system; I characterize my technique as a mix of
linear and visual note-taking.&lt;/p&gt;
&lt;p&gt;I haven'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 step.&lt;/p&gt;
&lt;p&gt;Capturing fleeting notes became almost automatic to me, but this step alone
doesn't produce useful notes.  I now believe the notes' value only emerges when
I do a second pass over my fleeting notes.&lt;/p&gt;
&lt;h1&gt;Who, What, When, Where, 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's goals.  When processing a
project-relevant fleeting note, I identify actions and define the project's
next 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't matter as long as
the note reaches the people involved.&lt;/p&gt;
&lt;h1&gt;Rephrase&lt;/h1&gt;
&lt;p&gt;If a note doesn'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 outlines.&lt;/p&gt;
&lt;p&gt;For example, I keep a list of tools I require for replacing my bike'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 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 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's essay  &lt;em&gt;Writes and Write
Nots&lt;/em&gt; reads as 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 more.&lt;/p&gt;
&lt;p&gt;Today generative AI tools may write for you, but they don't to the thinking
part.  Paul Graham's prediction that the world will split into those who
write and those who "write not".  Following his previous argument, this
means we will have a split between "thinks" and "think nots".&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 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't get the most out my 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 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
COVID-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 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This day marks the fifth anniversary of my Homelab.  Five years ago, as a
COVID-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 before.&lt;/p&gt;
&lt;p&gt;The current setup, which remained stable since 2020, doesn't represent the
first generation of my Homelab.  I started to use Ansible back in 2015 because
I had grown frustrated with the "install and forget" approach, where you
configure a system and then quickly forget the details, making future updates
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 LXC, an &lt;a href="https://owncloud.com/"&gt;ownCloud&lt;/a&gt; instance and a media
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's configuration but I couldn't build a reliable set of Ansible tasks and
playbooks that worked independently of machine'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' playbooks gradually stopped working because of the system updates and
other out of band 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 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 Nix.&lt;/p&gt;
&lt;p&gt;Happy birthday, 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 (AWS) Cloud Development Kit (CDK)
TypeScript library.  I have had extensive experience building on AWS, but I
haven't used this tool professionally.&lt;/p&gt;
&lt;p&gt;In this article I describe my experience …&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 (AWS) Cloud Development Kit (CDK)
TypeScript library.  I have had extensive experience building on AWS, but I
haven't used this tool professionally.&lt;/p&gt;
&lt;p&gt;In this article I describe my experience with the CDK and I will argue that, if
you can, you should prefer the CDK to any other tool when building cloud
infrastructure on AWS.&lt;/p&gt;
&lt;h1&gt;Infrastructure as code&lt;/h1&gt;
&lt;p&gt;Cloud providers such as AWS expose thousands of management endpoints to
programmatically interact with compute, storage and networking resources.  In
particular, AWS groups related endpoints into &lt;em&gt;services&lt;/em&gt;, such as EC2, S3, just
to name two out of more than 400 from their offering.&lt;/p&gt;
&lt;p&gt;I remember learning AWS back in 2018: I felt swamped by all the three letter
acronyms.  I didn't know if I needed EC2, ECS or EKS, or if EBS made more sense
for an instance inside a VPC.&lt;/p&gt;
&lt;p&gt;Initially, I studied the most commonly used services using the AWS web console
used services.  For example, I clicked on the "Launch new instance" button on
the EC2 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 permissions.&lt;/p&gt;
&lt;p&gt;While I appreciate the interactive and visual nature of the web console,
especially for learning, I can't build large systems by clicking around in my
web browser.&lt;/p&gt;
&lt;p&gt;I specify the system's blueprint in plain text files, as source code, which a
computer can translate into programmatic calls to the cloud provider's API.  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 evolves.&lt;/p&gt;
&lt;p&gt;I still use the web console every day, but mainly in "read-only" mode.  I
rarely use it to create or change resources, but I inspect and study the
resources the blueprint creates.&lt;/p&gt;
&lt;h1&gt;CloudFormation&lt;/h1&gt;
&lt;p&gt;AWS 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
YAML 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
tool.&lt;/p&gt;
&lt;p&gt;I believe AWS never wanted developers to write giant CloudFormation templates
by hand, but it didn't guide users what to do instead.  AWS 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 CDK which AWS announced in 2019 as their official CloudFormation
template generator.&lt;/p&gt;
&lt;h1&gt;Cloud Development Kit (CDK)&lt;/h1&gt;
&lt;p&gt;The AWS Cloud Development Kit (CDK) library, written in TypeScript, generates
CloudFormation templates.  AWS developed &lt;a href="https://github.com/aws/jsii"&gt;JSii&lt;/a&gt;, a technology to expose
the TypeScript CDK 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 CDK's programming
model to generate CloudFormation 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 CDK.  The library has
no dependencies, and it defines 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 blueprint.&lt;/p&gt;
&lt;p&gt;The CDK build process automatically generates large part of the CDK 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;AWS::S3::Bucket&lt;/a&gt; CloudFormation resource
to TypeScript.  The AWS 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;
constructs.&lt;/p&gt;
&lt;p&gt;You rarely use these generated objects because CDK 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;AWS's security recommendations&lt;/a&gt;.  Also, you can just 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 IAM policies so that the EC2 instance can read
objects from the 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;CDK Pipelines&lt;/a&gt; construct library
coordinates many AWS services to create a deployment pipeline for a CDK
application.  This library showed me the leverage the CDK offers: in just a few
lines of code, I could create a continuous deployment pipeline that deploys my
infrastructure into three regions using two AWS accounts.&lt;/p&gt;
&lt;p&gt;I admit, the first few times I read the documentation, I didn't pay close
attention to this layering.  When I develop with the CDK, I don'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 constructs.&lt;/p&gt;
&lt;p&gt;I view Layer 1 constructs as the platform's primitive operations.  Because
every AWS service integrates with CloudFormation, often from the day of its
public release, the corresponding Layer 1 construct quickly becomes available
in the CDK 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 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;VPC&lt;/a&gt; Layer 2 construct, for instance.  It comes with generous
defaults setting up two Availability Zones and NAT 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 IP addresses to instances running in a VPC, but this construct
doesn't allow for that; you'd have to build the missing bits using Layer 1
constructs.&lt;/p&gt;
&lt;p&gt;Even with these caveats, I'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 CloudFormation.&lt;/p&gt;
&lt;h2&gt;Escape hatches&lt;/h2&gt;
&lt;p&gt;You can import existing CloudFormation templates, written in YAML or JSON, and
treat them as CDK Constructs:  I had used a small CloudFormation template in my
project; it worked seamlessly, but after a few days I just rewrote it in
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't
cover all configuration options of a resource.  In this case you can fall back
to AWS SDK calls triggered on CloudFormation stack operation events such as
Create, Delete, or Update.  The CDK'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 coverage.&lt;/p&gt;
&lt;h2&gt;Tooling&lt;/h2&gt;
&lt;p&gt;The CDK'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'll call "appeal to familiarity" and one I certainly
don't disagree with.  But, looking again beyond the language syntax, I think
leveraging an existing programming library ecosystem provides the most benefit.&lt;/p&gt;
&lt;p&gt;When I started using the CDK I didn't know TypeScript.  I had used JavaScript
and many other programming languages, so learning the basics of TypeScript
didn'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 "CDK world", because the TypeScript scaffolding
just worked.&lt;/p&gt;
&lt;h1&gt;Difficulties&lt;/h1&gt;
&lt;p&gt;I praised the CDK's construct-based component model and its integration with
other AWS tools and with existing programming language ecosystems.  But during
my six months journey I faced also a few difficulties which I describe next.&lt;/p&gt;
&lt;h2&gt;Moving resources&lt;/h2&gt;
&lt;p&gt;I like maintaining code which groups resource definitions into high-level,
application-specific modules like "storage layer" or a "compute cell" because
the structure provides me context about a particular resource's role in the
application.  As I mentioned before, constructs provide a great modeling tool
for building up these modules.&lt;/p&gt;
&lt;p&gt;The CDK computes a resource'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 both.&lt;/p&gt;
&lt;p&gt;A technique I learned from the CDK documentation protects against accidental
resource destruction:  I add a unit test that asserts the stability of the
critical resource's logical identifier.&lt;/p&gt;
&lt;h2&gt;Using deferred 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's property.
During deployment, the CloudFormation service orders resource creation such
that it can substitute the &lt;code&gt;Ref&lt;/code&gt; with the property's actual value.&lt;/p&gt;
&lt;p&gt;The CDK 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 CDK translates 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 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;EKS Blueprints&lt;/h2&gt;
&lt;p&gt;The final point I want to make doesn't concern the CDK 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;EKS 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 CDK's existing construct programming
model. Also, this implementation heavily relies on async/await, which makes
escaping its patterns incredibly difficult.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;If you build on AWS, I suggest using the Cloud Development Kit.  You may have
reasons to choose something else, but I believe you should consider the CDK
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 AWS accounts,
deployment pipelines, and CDK code.  Finally, use any constructs from the CDK,
but think twice before importing other construct 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 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 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 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
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; puzzles.&lt;/p&gt;
&lt;h1&gt;Books&lt;/h1&gt;
&lt;p&gt;I read Liu Cixin's &lt;em&gt;Remembrance of Earth'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'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 TV adaptation.&lt;/p&gt;
&lt;p&gt;During vacation, I found Jack London'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 air.&lt;/p&gt;
&lt;p&gt;Thanks for reading my blog and happy 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 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 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'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 programs.&lt;/p&gt;
&lt;p&gt;I don'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 -- 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; -- I expressed the solution using this 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't have the energy to optimize 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 "gardens".  Initially I didn't find a good
approach for identifying a garden's boundary.  When I started to track the
normal of each point that form the boundary, my solution started to make 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 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 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's dynamic
bindings to write  code that solve both parts of the 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 fun.&lt;/p&gt;
&lt;p&gt;I couldn'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't have the motivation to go back to 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'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 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 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'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't need …&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'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't need extreme performance and I appreciate
its small size and light 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's just too slow even for browsing the 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;ZFS&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 LTS kernel, the HDMI port
and the sound didn'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
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 ZFS.&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 NixOS.&lt;/p&gt;
&lt;p&gt;The Raspberry Pi OS 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 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 NixOS.&lt;/p&gt;
&lt;p&gt;The Raspberry Pi OS 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 configuration.&lt;/p&gt;
&lt;p&gt;In my &lt;a href="https://github.com/wagdav/homelab"&gt;Homelab&lt;/a&gt; I don't use the Raspberry Pi OS, 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 configuration.&lt;/p&gt;
&lt;h1&gt;The "new" camera 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 stack.&lt;/p&gt;
&lt;p&gt;The new camera stack comprises four layers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Linux kernel with board-specific configuration&lt;/li&gt;
&lt;li&gt;Camera-specific drivers&lt;/li&gt;
&lt;li&gt;The libcamera library&lt;/li&gt;
&lt;li&gt;rpicam-apps camera utilities for taking photos and 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 OV5647) with my Raspberry Pi 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 default.&lt;/p&gt;
&lt;p&gt;Fortunately, it's easy to switch to a kernel tailored to the Raspberry Pi.  For
my model 3B, I select the &lt;code&gt;linux_rp3&lt;/code&gt; kernel 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'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 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 too.&lt;/p&gt;
&lt;h2&gt;Camera driver (OV5647)&lt;/h2&gt;
&lt;p&gt;The Raspberry Pi v1 camera module uses an Omnivision OV5647 image sensor.  We
need to describe the OV5647 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 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 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 the &lt;code&gt;compatible&lt;/code&gt; property from &lt;code&gt;bcm2835&lt;/code&gt; to &lt;code&gt;bcm2837&lt;/code&gt;.
It turns out the OV546 device tree overlay is compatible with both BCM
chipsets, but I don't understand why overlay's source doesn't reflect 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 I2C 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'm not entirely
satisfied:  fiddling with the device tree source files doesn't
feel right.&lt;/p&gt;
&lt;p&gt;Fortunately, the hardware configuration is done. Next, the software stack.&lt;/p&gt;
&lt;h2&gt;libcamera&lt;/h2&gt;
&lt;p&gt;The libcamera library drives the Raspberry Pi's camera system directly from the
Linux kernel, with minimal proprietary code running on the Broadcom GPU.&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'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 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
snippet, &lt;code&gt;old.mesonFlags&lt;/code&gt; refers to the upstream package's build flags.  The
overlay appends to the original flag list enabling the Raspberry Pi specific
Image Processing Algorithms (IPAs) and 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's build
instructions, like a &lt;em&gt;patch&lt;/em&gt; representing the differences between two versions
of a text 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 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 capabilities.&lt;/p&gt;
&lt;h1&gt;Picture 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
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 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'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 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'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 OS 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 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
controversial.&lt;/p&gt;
&lt;p&gt;I'm sure every team had heated discussions about software quality.  Yet …&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
controversial.&lt;/p&gt;
&lt;p&gt;I'm sure every team had heated discussions about software quality.  Yet, it'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 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 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's supposed to do,
  and does it 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 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 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 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 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 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
  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 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 --
development cost, user satisfaction or delivering on time -- to software
quality.  Of course it'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 it.&lt;/p&gt;
&lt;p&gt;The definition of quality is industry specific.  Just like the priority of the
quality attributes is project 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 "hard" 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 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 "-abilities" have deeply technical
aspects, therefore it is the responsibility of technical team to work towards
the desired quality 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 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's
impossible to measure software quality, but this doesn't mean it cannot be
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
organizations.&lt;/p&gt;
&lt;p&gt;The authors' 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
organizations.&lt;/p&gt;
&lt;p&gt;The authors' 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 benefits.&lt;/p&gt;
&lt;h1&gt;Stupidity 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 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 stupidity:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Lack of reflexivity&lt;/em&gt;: You don't think about your assumptions.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lack of justification&lt;/em&gt;: You don't ask why you're doing something.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lack of substantive reasoning&lt;/em&gt;: You don't consider the consequences or
   wider meaning of your 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 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
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 work.&lt;/p&gt;
&lt;h1&gt;Five kinds of Functional 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 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 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't guarantee quality, reliability and productivity.
People often blindly trust processes and systems which don'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 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's image and its everyday practices lead to frustration, low
commitment and 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't need or want into something that sounds exciting and
interesting.  But branding activities are often met with indifference and
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't mention bad news you often can't adapt to
important changes.  If you don'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 done.&lt;/p&gt;
&lt;h1&gt;Stupidity management&lt;/h1&gt;
&lt;p&gt;Although it'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 motivation.&lt;/p&gt;
&lt;p&gt;The third part enumerates four ways managers encourage functional 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 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's often about arguing that change is always good and about
  painting a rosy picture of the future absent of the past and present
  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's assumptions, its
  view of the word, and goals are self-evident, or 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 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 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 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 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've
  grown accustomed 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's their purpose? Perhaps even try to discontinue or cancel
  an activity or an arrangement.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I'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 --
characterized by the lack of reflexivity,  lack of justification and the lack
of substantive reasoning -- is everywhere in today's organizations.  This
sounds depressing.  Indeed, even the authors are 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 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
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 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 2023.&lt;/p&gt;
&lt;p&gt;At the beginning of the year reviewed Winston Royce'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 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This post is a short summary of the articles I wrote in 2023.&lt;/p&gt;
&lt;p&gt;At the beginning of the year reviewed Winston Royce'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's observations still apply 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 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 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; puzzles.&lt;/p&gt;
&lt;p&gt;Thanks for reading and happy 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 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 December.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: If you're still working or planning to work on the puzzles
stop reading 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'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 years.&lt;/p&gt;
&lt;p&gt;Usually I solved the day's problem before going to work, sometimes I coded a
bit in the evening to polish my 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 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 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 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 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'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't figure out how to
apply &lt;a href="https://en.wikipedia.org/wiki/Pick%27s_theorem"&gt;Pick's theorem&lt;/a&gt; to find
the 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 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 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
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 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
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 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 (Python)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jonathanpaulson/AdventOfCode/tree/master/2023"&gt;Jonathan Paulson (Python)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/odormond/adventofcode/tree/master/2023"&gt;Olivier Dormond (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 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 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'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 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 configuration.&lt;/p&gt;
&lt;p&gt;I wanted to reconfigure my servers automatically, triggered by committing to a
Git repository.&lt;/p&gt;
&lt;p&gt;To solve this problem I built a system based on Nix and freely available hosted
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 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 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 deployment.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Host 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 NUC 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 the &lt;code&gt;imports&lt;/code&gt; block you
can tell what is installed on this machine.  The host &lt;code&gt;nuc&lt;/code&gt; is my main home
server, it runs all my "production" services.&lt;/p&gt;
&lt;p&gt;For example, 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 managed.&lt;/p&gt;
&lt;h1&gt;Building with GitHub Actions&lt;/h1&gt;
&lt;p&gt;The NixOS host specifications are built with a 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 the &lt;code&gt;nuc&lt;/code&gt; machine: the kernel, the installed
packages and their configuration.  By 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 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
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 repository.&lt;/li&gt;
&lt;li&gt;Installs the QEMU static binaries for building packages for architectures
   different than that of the build 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 ARM 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 deploy.&lt;/li&gt;
&lt;li&gt;Pushes the built binaries to the cache and sends an activation signal to the
   Cachix Agent.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The job uses two secrets: &lt;code&gt;CACHIX_AUTH_TOKEN&lt;/code&gt; is the authentication token to
push to the binary cache and &lt;code&gt;CACHIX_ACTIVATE_TOKEN&lt;/code&gt; is required to activate
the built NixOS configurations.&lt;/p&gt;
&lt;h1&gt;Deploying with Cachix 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 installed &lt;code&gt;cachix-agent&lt;/code&gt; on the target hosts and configured a
few authentication 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 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 simple.&lt;/p&gt;
&lt;h1&gt;Acknowledgement&lt;/h1&gt;
&lt;p&gt;I'm grateful to &lt;a href="https://www.cachix.org/"&gt;Cachix Deploy&lt;/a&gt; for offering a binary
cache and a deployment 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
ARM 64 architecture, which Nix refers to as &lt;code&gt;aarch64-linux&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To build &lt;code&gt;aarch64-linux&lt;/code&gt; binaries we can:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build natively on an &lt;code&gt;aarch64-linux&lt;/code&gt; machine.&lt;/li&gt;
&lt;li&gt;Cross compile for &lt;code&gt;aarch64-linux&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Compile with an 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
ARM 64 architecture, which Nix refers to as &lt;code&gt;aarch64-linux&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To build &lt;code&gt;aarch64-linux&lt;/code&gt; binaries we can:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build natively on an &lt;code&gt;aarch64-linux&lt;/code&gt; machine.&lt;/li&gt;
&lt;li&gt;Cross compile for &lt;code&gt;aarch64-linux&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Compile with an 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 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 ARM 64 computer for building, if you own or rent 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 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 QEMU.&lt;/p&gt;
&lt;h1&gt;On NixOS&lt;/h1&gt;
&lt;p&gt;On NixOS, it's trivial to use QEMU 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
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 QEMU 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, 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 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
source.&lt;/p&gt;
&lt;p&gt;If the compilation with the emulated tool chain works, Nix writes an ARM 64-bit
binary at &lt;code&gt;./result/bin/hello&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;Using GitHub 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
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 Nix:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the QEMU 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 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 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 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 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;"waterfall" method&lt;/a&gt;,
a model that considers the project's activities as a linear sequence of steps.
In fact, this figure …&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 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;"waterfall" method&lt;/a&gt;,
a model that considers the project'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't work&lt;/em&gt; in practice and he suggests five
concrete steps that are required for large software projects to succeed.&lt;/p&gt;
&lt;h1&gt;Analysis and 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 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'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 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 systems:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"[...] to manufacture larger software systems [...] additional development
steps are required, none contribute as directly to the final product as
analysis and coding, and all drive up the development costs."&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't understand that a software
project is much more than just coding:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&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 groups."&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 it.&lt;/p&gt;
&lt;p&gt;The author managed the &lt;em&gt;"development of software packages for spacecraft
mission planning, commanding and post-flight analysis"&lt;/em&gt;.  Drawn from the
author's experience, the paper proposes a development model that is required,
but not sufficient, for such software project to 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's foolish to extrapolate to the development of &lt;em&gt;any&lt;/em&gt; software project.&lt;/p&gt;
&lt;h1&gt;Not waterfall&lt;/h1&gt;
&lt;p&gt;The third paragraph introduces the "additional steps" the author hinted in the
introduction:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&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 step."&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's perspective, Royce continues:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&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 resources."&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't specify how these steps are executed.  In
fact, he doesn't discuss this figure any further because this is just an
intermediate step, and he's not finished presenting his model yet.&lt;/p&gt;
&lt;h1&gt;Local iterations are insufficient&lt;/h1&gt;
&lt;p&gt;In Figure 3, Royce shows an iterative relationship between successive
development 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 because:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"[...] as each step progresses and the design is further detailed [...] The
virtue of all of this is that as the design proceeds the change process is
scoped down to manageable limits."&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;"risky and invites failure"&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 example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&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. [...] if these phenomena fail to
satisfy the various external constraints, then invariably a major redesign is
required."&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 late.&lt;/p&gt;
&lt;p&gt;Before discussing the mitigations, Royce closes this section with a note on the
role of coding:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&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 testing."&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 process.&lt;/p&gt;
&lt;h1&gt;Eliminate development 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 are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Program design comes first&lt;/li&gt;
&lt;li&gt;Document the design&lt;/li&gt;
&lt;li&gt;Do it twice&lt;/li&gt;
&lt;li&gt;Plan, control and monitor testing&lt;/li&gt;
&lt;li&gt;Involve the customer&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The process is shown in Figure 4, let's see each steps in 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 first&lt;/h2&gt;
&lt;p&gt;In center of Figure 4 is "Program design", 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 prescriptive:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&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 procedures."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The outcome of this phase is an overview document with a goal that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&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 document."&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't understand.&lt;/p&gt;
&lt;h2&gt;Document the design&lt;/h2&gt;
&lt;p&gt;Royce starts the longest section of the paper with a categorical statement:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"The first rule of managing software development is ruthless enforcement of
documentation requirements. [...] Management of software is simply impossible
without a high degree of documentation."&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's progress nor its 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
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 long.&lt;/p&gt;
&lt;h2&gt;Do it 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;"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 concerned."&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 work.&lt;/p&gt;
&lt;h2&gt;Plan, control and monitor 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 points.&lt;/p&gt;
&lt;p&gt;If the project followed the previous steps, most problems should be already
solved:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&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
phase."&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 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% coverage.&lt;/p&gt;
&lt;h2&gt;Involve the 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 review.&lt;/p&gt;
&lt;h1&gt;Discussion&lt;/h1&gt;
&lt;p&gt;I am surprised how many ideas, that we consider as "modern", 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 today.&lt;/p&gt;
&lt;p&gt;More than fifty years later, I feel that the Royce's wisdom remains relevant.
Many suggestions in this paper were rediscovered or reformulated later, perhaps
some are still 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 it.&lt;/p&gt;
&lt;h1&gt;Acknowledgements&lt;/h1&gt;
&lt;p&gt;The figures in this article are from the original 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 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 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
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 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; puzzles.&lt;/p&gt;
&lt;p&gt;Thanks for reading and happy 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 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 December.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: If you're still working or planning to work on the puzzles
stop reading 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'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's a good fit for the Advent of
Code.  Clojure'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 hand.&lt;/p&gt;
&lt;p&gt;I wanted to write idiomatic, readable code.  I don't compete on the global
leaderboard, I don't care about coding speed, code size and 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's problem
before going to work, sometimes I coded a bit in the evening to polish my
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'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 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 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 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 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
"interesting" boundary conditions.  I loved the plot twist in the second part
which I don't want to spoil.  Many people gave up here, so I'm proud I made it.
Later I'd like to generalize my solution because now it only works on the input
generated for my 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'll recognize
similar problems to solve all days on my 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 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 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 (Julia)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jonathanpaulson/AdventOfCode/tree/master/2022"&gt;Jonathan Paulson (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 (Go)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/odormond/adventofcode/tree/master/2021"&gt;Olivier Dormond (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 (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 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's segments, but we don'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
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 renders.&lt;/p&gt;
&lt;p&gt;For example, the first signal pattern &lt;code&gt;"be"&lt;/code&gt; must be the digit &lt;code&gt;1&lt;/code&gt; because this
is the only digit that is rendered using two segments.  But we don't know which
segment the signals &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;e&lt;/code&gt; are connected.  By looking at the digit &lt;code&gt;1&lt;/code&gt;
there are two 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 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 information.&lt;/p&gt;
&lt;p&gt;For example, the 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 digit &lt;code&gt;3&lt;/code&gt; by exploiting that the rendering of
the digit &lt;code&gt;3&lt;/code&gt; doesn't change with the digit &lt;code&gt;1&lt;/code&gt; superimposed.  In other words,
the activation signals of the digit &lt;code&gt;3&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; only differ in one segment.&lt;/p&gt;
&lt;h1&gt;Imperative 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 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 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 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 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 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 it.&lt;/p&gt;
&lt;h1&gt;Declarative solution&lt;/h1&gt;
&lt;p&gt;In this section we reimplement 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 works.&lt;/p&gt;
&lt;p&gt;Let's see the declarative version of the pattern decoder in Clojure 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 of
&lt;code&gt;decode-logic&lt;/code&gt; is a set of constraints derived from our original problem
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 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 solution.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Search the 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 section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Identify the "easy" digits, those with unambiguous number of active
   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
   sequences &lt;code&gt;[2, 3, 5]&lt;/code&gt; and &lt;code&gt;[0, 6, 9]&lt;/code&gt;, 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
   other.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The sequence of activation patterns is a permutation of the 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's execution.  In fact, you can rearrange the constraints arbitrarily,
the logic expression evaluates to the same result.&lt;/p&gt;
&lt;p&gt;The order of the constraints, however, affects the solver's performance: I
found that stating more specific constraints first makes the solver explore the
possible states faster.&lt;/p&gt;
&lt;p&gt;The beauty of the declarative solution comes with a price, at least in my
implementation: &lt;code&gt;decode-logic&lt;/code&gt; takes approximately six seconds to run where
&lt;code&gt;decode&lt;/code&gt; completes within a millisecond.  This was my first logic program I've
ever written in Clojure core.logic so I guess this is 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's performance is harder than compared
to an imperative 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
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 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'd like to
experiment more with various machine learning 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 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 language.&lt;/p&gt;
&lt;p&gt;Thanks for being here, let's see what 2022 brings!&lt;/p&gt;
&lt;p&gt;Happy New 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 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 December.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: If you're still working or planning to work on the puzzles
stop reading 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'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 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
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 language.&lt;/p&gt;
&lt;p&gt;Just like last year, I didn't care about code size, performance optimizations
(only when it was the goal of the puzzle) and coding 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 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 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's threading macros and 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
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 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
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's a lot to learn from the conversations 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't see the point in
deciphering someone else's obfuscated code.  I do this enough at work already.&lt;/p&gt;
&lt;h1&gt;Learning 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 Clojure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;REPL&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 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'm using other languages I run the tests from a separate command terminal.
  With Clojure it's easy to run the tests without leaving my 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
  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's literal
  regular expressions syntax and the function &lt;code&gt;re-seq&lt;/code&gt;, which returns a
  sequence of successive matches, are 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
constructs.&lt;/p&gt;
&lt;p&gt;In the past few weeks coding in Clojure I find this claim justified.  In the
future I'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
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 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 (Go)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/odormond/adventofcode/tree/master/2021"&gt;Olivier Dormond (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 (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 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's time to move 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 company.&lt;/p&gt;
&lt;h1&gt;Calibration Team&lt;/h1&gt;
&lt;p&gt;I joined Pix4D'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;'s image processing 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 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 product.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Integration 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 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 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 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'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 Team&lt;/h1&gt;
&lt;p&gt;At the end of 2019 I was invited to join Cloud Services, the team responsible
for Pix4D'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 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 system.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Worst times:&lt;/em&gt; Browsing through a hundred SQS queues trying to
  reverse-engineer what they're 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 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'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 systems.&lt;/p&gt;
&lt;p&gt;I wish everybody at Pix4D a lot of 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 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 work.&lt;/p&gt;
&lt;h1&gt;Discovering 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 practices.&lt;/p&gt;
&lt;p&gt;One summer I read &lt;a href="https://basecamp.com/books/rework"&gt;REWORK&lt;/a&gt;, a book written by Basecamp's founders.  The
chapter &lt;em&gt;Hire great writers&lt;/em&gt; explains the authors' 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't plan to hire anybody, but the
emphasis on high-quality writing inspired me to become a better 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 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 most.&lt;/p&gt;
&lt;h1&gt;Book: BUGS In Writing&lt;/h1&gt;
&lt;p&gt;The book &lt;a href="https://www.amazon.com/BUGS-Writing-Revised-Guide-Debugging/dp/020137921X"&gt;BUGS 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 photos.&lt;/p&gt;
&lt;p&gt;I encountered this book through a reference in Chris Okasaki'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's copy
of Lyn Dupré's BUGS 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 book.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I read this recommendation I immediately ordered a copy.  &lt;em&gt;BUGS 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 book.&lt;/p&gt;
&lt;p&gt;To give a taste of Dupré's style, here'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
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 in.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here the principle is that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[...] 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 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 decreases.&lt;/p&gt;
&lt;h1&gt;Book: On Writing 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 memoirs.&lt;/p&gt;
&lt;p&gt;Zinsser warns about clutter, every piece of text that doesn'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 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 it.&lt;/p&gt;
&lt;h1&gt;Writing a 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'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;LED and a
button&lt;/a&gt; to a Raspberry Pi.  Unexpectedly, I had a few "hits" 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'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 reachable.&lt;/p&gt;
&lt;h1&gt;Writing at 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's hard to see the context in which a given pull-request makes 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't know how to
write them 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'd read
the document you would have known what's been done and what'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 today.&lt;/p&gt;
&lt;p&gt;During this process I found a few practices 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 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 insufficient.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I often reference related content.  There's no need to repeat what's
  explained 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
  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's too big.  If a few words can't express what I'm doing, the
project is ill-defined, or I lack some knowledge to execute 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
"evolving" documents on the company's internal 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' idioms express the same 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' idioms express the same 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 sources.&lt;/p&gt;
&lt;h1&gt;Random 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 original.&lt;/p&gt;
&lt;p&gt;Here's an example generated sentence, given the words of all articles of this
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 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 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 words.&lt;/p&gt;
&lt;p&gt;For example, let'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'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 from.&lt;/p&gt;
&lt;h1&gt;Rust implementation&lt;/h1&gt;
&lt;p&gt;I wrote my version of the word generator program in Rust.  This code snippet
shows its basic 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 word.&lt;/li&gt;
&lt;li&gt;Add words from the input text and store them in a hash-map internally.&lt;/li&gt;
&lt;li&gt;Finish building and create the actual &lt;code&gt;Chain&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;Chain&lt;/code&gt; to generate 100 words and print them as a sentence.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The whole implementation is 129 lines long and it's available on
&lt;a href="https://github.com/wagdav/markov"&gt;GitHub&lt;/a&gt;.  It'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 AWK 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'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 text.&lt;/p&gt;
&lt;h2&gt;Book of 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...&lt;/em&gt;)
which provides chains with large suffix sets.  I started to test my program
with this data set.  Here's one 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 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 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'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 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 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 word.&lt;/p&gt;
&lt;p&gt;Here's another 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 solved.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Blog corpus&lt;/h2&gt;
&lt;p&gt;Finally I tried to generate a random blog post using the articles I've written
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've written
to plain 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 articles:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In this representation we can assume that we exploit that IO 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 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 YAML’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 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 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 "style" 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 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 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 Nix.&lt;/p&gt;
&lt;h1&gt;Container 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's runtime system creates one or many container
instances based on the provided image and runs your application using some form
of isolation.&lt;/p&gt;
&lt;p&gt;Typically the application doesn'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 image.&lt;/p&gt;
&lt;h1&gt;Dockerfile&lt;/h1&gt;
&lt;p&gt;The canonical way of creating container images is via a &lt;code&gt;Dockerfile&lt;/code&gt;.  For
example, let'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 this
&lt;code&gt;Dockerfile&lt;/code&gt;.  Let's see them, line by 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'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't specify the exact version, every time you build this image
   you may install different versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We install &lt;code&gt;pip&lt;/code&gt; which we'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 well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We copy the &lt;code&gt;requirements.txt&lt;/code&gt; to the image.  This also only required for
   building the 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.  If &lt;code&gt;requirements.txt&lt;/code&gt; specifies exact version numbers we know
   exactly which packages will be in the final 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 case.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We copy an HTML template, also required during 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,
the &lt;code&gt;Dockerfile&lt;/code&gt;'s imperative language fails to capture precisely our
application's 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 example: &lt;code&gt;pip&lt;/code&gt;, &lt;code&gt;apk&lt;/code&gt;, and
  &lt;code&gt;requirements.txt&lt;/code&gt; are not needed in the final 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's not clear which ones are actual 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 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 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 files.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We find &lt;code&gt;Dockerfiles&lt;/code&gt; with such structure used by many software projects.  I
took this section'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'll see how novice users  write their &lt;code&gt;Dockerfiles&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Dockerfile from scratch&lt;/h1&gt;
&lt;p&gt;The ideal container image contains the application and the application'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 called &lt;code&gt;weather-data-collector&lt;/code&gt; using the 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's locally built executable on the image'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 section.&lt;/p&gt;
&lt;p&gt;There's a limitation though: this &lt;code&gt;Dockerfile&lt;/code&gt; assumes that the application is
built as a single, statically linked binary.&lt;/p&gt;
&lt;p&gt;Also, by reading this &lt;code&gt;Dockerfile&lt;/code&gt; we don't know anything about provenance of
the application's binary: which build commands were executed, which tool chain
version is used, what additional libraries were installed before building.  To
remedy this it'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's
binary.  Then, during second stage, the binary is copied into an independent
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's
native build instructions.&lt;/p&gt;
&lt;h1&gt;Blame your build system&lt;/h1&gt;
&lt;p&gt;I don't believe that writing 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's dependencies.  The various &lt;code&gt;Dockerfile&lt;/code&gt; tricks are just
workarounds for the absence of proper dependency management.&lt;/p&gt;
&lt;p&gt;Take a look at &lt;em&gt;any&lt;/em&gt; non-trivial project's build instructions.  I bet you'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's build system.&lt;/p&gt;
&lt;p&gt;This is admitting that the project's dependency lists are incomplete and you
need out-of-band manipulations such as installing a package or downloading
something else from the Internet.&lt;/p&gt;
&lt;h1&gt;Container images with 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's dependencies and &lt;em&gt;nothing else&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To demonstrate, here's an example which packages the HTML pages of this blog
and a web server into a container 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 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 visit &lt;code&gt;http://localhost:8000&lt;/code&gt; you can read my articles served from the
locally running 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 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's
arguments define the image's name, contents and its configuration according to
the &lt;a href="https://opencontainers.org"&gt;OCI&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 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 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 files.&lt;/p&gt;
&lt;p&gt;To 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 languages.&lt;/p&gt;
&lt;p&gt;Concretely, for the example showed in this section,  you can find the complete
definition 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 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 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;QEMU, 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; 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 application.&lt;/p&gt;
&lt;p&gt;Using Nix and the Nix Packages Collection it's possible to build minimal,
reproducible container images with a few lines of code which run locally and on
any hosted build automation 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 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 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 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 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'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 pipelines.&lt;/p&gt;
&lt;p&gt;In the second part of the year I'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 too.&lt;/p&gt;
&lt;p&gt;In summary, the articles I wrote over the past year fall in three broad
categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Concepts and configuration of build automation software&lt;/li&gt;
&lt;li&gt;Infrastructure and Nix&lt;/li&gt;
&lt;li&gt;Learning the Rust language&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Looking forward to seeing what 2021 brings!&lt;/p&gt;
&lt;p&gt;Happy New 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 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
December.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: If you're still working or planning to work on the puzzles
stop reading 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'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 "hard" requirement, the rest was just to have fun.
After solving the first couple of puzzles I set the following boundaries for
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; crates.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Independent programs&lt;/em&gt;: Each day's solution is a separate, independent
  executable with no code reuse among the 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'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 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 attempt.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also decided what were &lt;em&gt;not&lt;/em&gt; my 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 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 puzzle.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Code performance&lt;/em&gt;:  I didn't measure or optimize my code's performance
  in any way.  Nevertheless, the execution time of every solution is less than
  a few 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'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 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's shunting yard
algorithm&lt;/a&gt; and I used it to transform the expressions specified
in infix notation to reverse Polish 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 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 again...&lt;/p&gt;
&lt;h1&gt;In the 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 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 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 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't connect to the problem because I found it too
  convoluted.  After I looked at other people's solution it was clear that I
  was missing the underlying search algorithm therefore my implementation
  turned out to be less than great.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Learning Rust&lt;/h1&gt;
&lt;p&gt;Solving these puzzles was great for learning Rust. From these last three weeks
I'd underline these 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 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's easy to add tests and maintain tests because the test code is
  close to the application 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'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 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
  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
  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 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 dimensions.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Regex crate&lt;/em&gt;:  Well, regular expressions are just everywhere.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;enum&lt;/em&gt;: In Rust &lt;code&gt;enum&lt;/code&gt; is a real sum type where the variants can contain data
  too. I used 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 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'm missing
something: a data structure, an algorithm or a language feature.  The hard part
is to figure out which 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 CI 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 that.&lt;/p&gt;
&lt;p&gt;This article is about the changes I made in this blog's deployment …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In July I described how I use Travis CI 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 that.&lt;/p&gt;
&lt;p&gt;This article is about the changes I made in this blog's deployment process
during the last months. These include switching to Nix Flakes, adding more
checks to the pipeline and moving from Travis CI to GitHub 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 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 function &lt;code&gt;outputs&lt;/code&gt; takes the project'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'll see a concrete example of the &lt;code&gt;checks&lt;/code&gt;
attribute in subsequent section.  There's an ongoing effort to define a
standard structure for the returned value so that specific tools can understand
and use the built 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 CI system.&lt;/p&gt;
&lt;p&gt;To learn more about Flakes I recommend the following 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'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;RFC documenting the flake'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 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 running &lt;code&gt;nix-build&lt;/code&gt; in the source 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 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 binary?&lt;/p&gt;
&lt;p&gt;Language-specific package managers such 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 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 flake's &lt;code&gt;outputs&lt;/code&gt;
function describes self-tests.  For this blog's source the checks look like
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's only one:
&lt;code&gt;x86_64-linux&lt;/code&gt;.  For this blog's source &lt;em&gt;checking&lt;/em&gt; means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build the static the blog's static HTML files&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;shellcheck&lt;/code&gt; on all scripts in the source code&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;mdl&lt;/code&gt; on all markdown files in the source code&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;yamllint&lt;/code&gt; on all YAML files in the source 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 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 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
installed.&lt;/p&gt;
&lt;h1&gt;GitHub Actions&lt;/h1&gt;
&lt;p&gt;Previously the build and deployment scripts ran on Travis CI.  I was curious to
see how the deployment would work on GitHub Actions, which has become popular
during the past year.&lt;/p&gt;
&lt;p&gt;The transition from Travis CI 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 steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check out the repository&lt;/li&gt;
&lt;li&gt;Install Nix using Cachix'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 checks&lt;/li&gt;
&lt;li&gt;Deploy the site if on the master branch&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The workflow is not concerned with installing or configuring anything but Nix
and it's merely coordinating the build and deploy 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 CI/CD systems such as GitHub Actions and
Travis CI.  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
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
artifacts.&lt;/p&gt;
&lt;p&gt;In this article I describe, Kevlar, an experimental build automation tool that
tries to build on these concepts.&lt;/p&gt;
&lt;h1&gt;Programming in YAML&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 with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Few dozen developers&lt;/li&gt;
&lt;li&gt;Handful of projects&lt;/li&gt;
&lt;li&gt;Couple of programming 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 CI was a a
major player, GitLab was on the rise, GitHub Actions and CircleCI didn't
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 CI&lt;/a&gt; in our data centers.  Concourse
served us well: today Pix4D's continuous integration system builds more
libraries and products than ever.  Concourse uses YAML for describing its
pipelines which model the software delivery process.  And YAML started to
sprout everywhere.&lt;/p&gt;
&lt;p&gt;Although YAML 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 repetitive.&lt;/p&gt;
&lt;p&gt;To allow for reusing pipeline code build automation systems introduced ad-hoc
concepts and workarounds.  Some examples 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;YAML 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 Variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vito/oci-build-task"&gt;Reusable build 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 YAML's 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's try
to use these concepts to express software delivery pipelines.&lt;/p&gt;
&lt;h1&gt;Enter Kevlar&lt;/h1&gt;
&lt;p&gt;I found programming in YAML 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 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 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 actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clone the source 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 repository.&lt;/li&gt;
&lt;li&gt;Start a container from the build image and execute the build 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 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's image built.&lt;/p&gt;
&lt;p&gt;The syntax may be unusual, but it's just regular Haskell code.  This could have
been easily written in YAML 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 packages.&lt;/p&gt;
&lt;p&gt;Let's continue building Kevlar's own pipeline by adding a publish 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 the &lt;code&gt;build&lt;/code&gt; function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clone the source repository.&lt;/li&gt;
&lt;li&gt;Build a Docker image with the tools required for releasing the binary artifacts.&lt;/li&gt;
&lt;li&gt;Start a container from the built image and execute the publish script.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;publish&lt;/code&gt; functions we can succinctly define Kevlar's
build-and-release 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 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'd expect: the pipeline builds and
publishes the built binaries running both steps in dedicated Docker containers.&lt;/p&gt;
&lt;p&gt;We may refer to the functions &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;publish&lt;/code&gt; as "steps" and the function
&lt;code&gt;buildAndPublish&lt;/code&gt; as the final "pipeline".  In Kevlar they are all represented
as functions returning a &lt;code&gt;Task&lt;/code&gt; value.&lt;/p&gt;
&lt;p&gt;The function &lt;code&gt;buildAndPublish&lt;/code&gt; defines the following graph of 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 opportunities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We could run the image building steps in parallel because they don't use each
  other's output.&lt;/li&gt;
&lt;li&gt;We could avoid cloning the repository twice and reuse the repository's local
  copy in downstream steps.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The next sections expand on these ideas in detail.&lt;/p&gt;
&lt;h2&gt;Automatic 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 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
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'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 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't need to be aware of any of this
and the pipeline remains a regular Haskell function.&lt;/p&gt;
&lt;p&gt;Today'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 process.&lt;/p&gt;
&lt;p&gt;In Kevlar the user is only concerned with data dependencies.  The system makes
sure that the pipeline's task run in the right order as fast as possible.&lt;/p&gt;
&lt;h2&gt;Incremental 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 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've seen an example of this in the
previous section where the repository's local copy was passed to start building
the two container images 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't find a satisfactory solution to this in Kevlar.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Frustrated by the verbose YAML configuration used by popular build automation
tools I wrote Kevlar, an experimental system, where the pipeline configuration
is expressed in a functional programming 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 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 designs.&lt;/p&gt;
&lt;p&gt;I also realized that I'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 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 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 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 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 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'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 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'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.  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
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 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's async library uses the same primitives as Go: the syntax is LISP, 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's presentation&lt;/a&gt; if you're interested how this
works on the JVM and in a web browser using 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's succint and
expressive.  We don'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'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 API.&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've been learning for the last couple of 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't see channels
and explicit thread management here either.  The Rust language defines 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'd like to explore other libraries too and learn more about how
they 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're interested how this feature was designed I recommend
watching &lt;a href="https://www.youtube.com/watch?v=lJ3NC-R3gSI"&gt;Steve Klabnik'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 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've been manually deploying this blog to &lt;a href="https://pages.github.com/"&gt;GitHub
Pages&lt;/a&gt;.  This worked OK 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 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For a long time I've been manually deploying this blog to &lt;a href="https://pages.github.com/"&gt;GitHub
Pages&lt;/a&gt;.  This worked OK 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 HTML 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
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't have to manage
any servers.  GitHub expects the HTML 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 repository.&lt;/p&gt;
&lt;p&gt;I configured &lt;a href="https://travis-ci.org/"&gt;Travis CI&lt;/a&gt; to execute the build and deploy steps when a change
is committed to the source repository.&lt;/p&gt;
&lt;p&gt;In 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 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
  HTML pages.&lt;/li&gt;
&lt;li&gt;When triggered, Travis CI checks out the source repository, builds the blog
  and pushes the generated files to the deployment repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's see the build and deploy steps in 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't
explain how it works, but I highlight the steps it performs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build the static website using 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 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 manager.&lt;/p&gt;
&lt;p&gt;To execute all the checks and build the blog I 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 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 HTML files to the
deployment 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't have to install any additional tools or libraries to run 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
CI&lt;/a&gt; to automate the build, check and deployment steps.&lt;/p&gt;
&lt;p&gt;The Nix support of Travis CI is fantastic: it takes only &lt;a href="https://github.com/wagdav/thewagner.net/blob/3e423bb/.travis.yml"&gt;seven lines of sweet
YAML&lt;/a&gt; to setup 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 the &lt;code&gt;master&lt;/code&gt; branch.  The secret value
&lt;code&gt;GITHUB_TOKEN&lt;/code&gt; is configured on the Travis CI web 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 HTML 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 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've changed.  I tried Ansible but I found it tedious to
maintain …&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've changed.  I tried Ansible but I found it tedious to
maintain playbooks: it's hard to remove all assumptions about the current state
of the system you're configuring and making all playbook tasks idempotent is
close to 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 DSL box of my Internet service
provider (ISP).  I change the default settings of this device as little as
possible because, in my experience, these ISP provided boxes break or get
replaced every other year.&lt;/p&gt;
&lt;p&gt;When I have a problem with the box and I call the ISP'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't
want my home network setup to depend on specific features of the ISP-provided
box.&lt;/p&gt;
&lt;p&gt;I have a Linksys WRT3200ACM router connected to the ISP'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 DNS aliases, install the Prometheus OpenWRT node exporter.&lt;/p&gt;
&lt;h1&gt;NixOS 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 include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Old industrial PC (32-bit)&lt;/li&gt;
&lt;li&gt;Intel NUC (64-bit)&lt;/li&gt;
&lt;li&gt;Raspberry Pi 4 (64-bit ARM)&lt;/li&gt;
&lt;li&gt;Thinkpad laptop (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
well.&lt;/p&gt;
&lt;p&gt;Previously I tried managing servers using Salt and Ansible and I'm never
looking 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 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 components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable and configure 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 discovery&lt;/li&gt;
&lt;li&gt;Open a port in the 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 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, the &lt;code&gt;scrapeConfigs&lt;/code&gt; attribute, which I elided 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
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 JSON
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 GPIO ports of a LED controller equipped with an infrared receiver are
assigned like 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 MQTT.  Then, a &lt;a href="https://www.influxdata.com/time-series-platform/telegraf/"&gt;Telegraf&lt;/a&gt; service
exports the MQTT 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 MQTT-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 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 configuration&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Gitolite:&lt;/em&gt; Host private Git repositories&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Grafana:&lt;/em&gt; Display metrics on dashboards&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Mosquitto MQTT broker:&lt;/em&gt; relay messages from the sensors&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Nginx:&lt;/em&gt; HTTP server and reverse proxy&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Prometheus and its exporters:&lt;/em&gt; Collect metrics&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Telegraf:&lt;/em&gt; Export MQTT sensor data as Prometheus metrics&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the future I'm planning to configure WireGuard VPN 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 servers.&lt;/p&gt;
&lt;p&gt;Overall I'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 minutes.&lt;/p&gt;
&lt;h1&gt;Acknowledgment&lt;/h1&gt;
&lt;p&gt;I'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'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 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 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For the last few weeks I'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 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
reliable.&lt;/p&gt;
&lt;h1&gt;The 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 languages.&lt;/p&gt;
&lt;p&gt;Let blocks bind values to symbols. The bindings appear after the keyword &lt;code&gt;let&lt;/code&gt;
and the symbols can be used after the keyword &lt;code&gt;in&lt;/code&gt;.  For example, the
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 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 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 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 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 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's make this
statement more concrete with an example.&lt;/p&gt;
&lt;p&gt;We will use Nix to put a string into a file using a build action equivalent 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 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 use &lt;code&gt;bash&lt;/code&gt;
but from where do we get its executable?&lt;/p&gt;
&lt;p&gt;Typical build systems assume that certain programs are available in the build
environment.  Nix doesn't make such assumptions.  Builds are performed in
isolation: no programs, no environment variables, nor access to the outside
world are available unless explicitly specified.&lt;/p&gt;
&lt;p&gt;In programming we use a function to abstract over an input parameter of a
computation.  Let's do the same and write a function which takes &lt;code&gt;bash&lt;/code&gt; as
input and returns the build recipe, a 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'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's architecture where this
derivation can be 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 the &lt;code&gt;hello&lt;/code&gt; derivation.&lt;/p&gt;
&lt;p&gt;To understand better the derivation's structure, let's assume we have &lt;code&gt;bash&lt;/code&gt;
built and we evaluate the &lt;code&gt;hello&lt;/code&gt; derivation.  Nix stores the resulting
derivation in the following 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 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 name.&lt;/p&gt;
&lt;p&gt;This data structure is a concrete description how to build 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 named &lt;code&gt;out&lt;/code&gt;.  The output will be
  stored under the given 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 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 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 PC the expression &lt;code&gt;builtin.currentSystem&lt;/code&gt; evaluates 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 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's attributes we provided in the Nix
  expression.  We reference &lt;code&gt;$out&lt;/code&gt; in the build 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 derivations.&lt;/p&gt;
&lt;p&gt;Nix builds a component in two stages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Evaluates the expression and writes resulting derivations in the Nix store.&lt;/li&gt;
&lt;li&gt;Builds the derivation and writes build results in the Nix 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 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 hardware.&lt;/p&gt;
&lt;h1&gt;Build the example&lt;/h1&gt;
&lt;p&gt;To build the example in the previous section, save the expression in a file
named &lt;code&gt;hello.nix&lt;/code&gt; and 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 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 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's easy to verify if we find the
string we 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 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 section.&lt;/p&gt;
&lt;h1&gt;Composing an operating 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
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
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 in &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt;, is a module itself which may include
other 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 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 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 try.&lt;/p&gt;
&lt;p&gt;You don'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're 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 more&lt;/h1&gt;
&lt;p&gt;This section is a collection of online resources which I find useful to learn
about Nix.&lt;/p&gt;
&lt;p&gt;Learn the Nix 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 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 Manual&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Learn about modules and 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 options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nixos.org/nixos/packages.html"&gt;Search NixOS packages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nixos.org/nixos/options.html"&gt;Search NixOS options&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Read about the original 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 Maak)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://edolstra.github.io/pubs/phd-thesis.pdf"&gt;The Purely Functional Software Deployment 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'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 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 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 ALGOL and now they are part of all mainstream
programming 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 ALGOL and now they are part of all mainstream
programming 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
infrastructure.&lt;/p&gt;
&lt;p&gt;We need to change our mindset.&lt;/p&gt;
&lt;h1&gt;Automate 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 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; (C++)&lt;/li&gt;
&lt;li&gt;Tracing garbage collection (Java, Python, Go, Haskell)&lt;/li&gt;
&lt;li&gt;Ownership tracking (Rust)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Would it be possible to make parallelism, that is allocation of code to
processors, automatic?&lt;/p&gt;
&lt;p&gt;With automatic memory management we stopped 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 sixties.&lt;/p&gt;
&lt;h1&gt;Accidentally complex&lt;/h1&gt;
&lt;p&gt;Let's take the textbook example of 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's most common programming style: sequential,
imperative, mutable and allowing uncontrolled side effects.  Every line of this
function states what happens during execution:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Assign an initial value to &lt;code&gt;result&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use the value of &lt;code&gt;i&lt;/code&gt; drawn from the specified range.&lt;/li&gt;
&lt;li&gt;Mutate &lt;code&gt;result&lt;/code&gt; with the current value of &lt;code&gt;i&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Many consider this implementation "readable" and "simple" because we are used
to seeing such programs.  But this code contains many &lt;em&gt;accidental&lt;/em&gt; aspects: the
&lt;code&gt;result&lt;/code&gt; accumulator, the intermediate 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 essential&lt;/h1&gt;
&lt;p&gt;Let's strip off everything but the essential from the previous implementation
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 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 factors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For small &lt;code&gt;n&lt;/code&gt; execute sequentially.&lt;/li&gt;
&lt;li&gt;For large &lt;code&gt;n&lt;/code&gt; split the range among multiple processors, then merge the
  results.&lt;/li&gt;
&lt;li&gt;Push some parts of the computation to the GPU.&lt;/li&gt;
&lt;li&gt;Send the computation to a massively parallel 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 environment.&lt;/p&gt;
&lt;h1&gt;Algebraic properties&lt;/h1&gt;
&lt;p&gt;If we recognize and communicate our problem's algebraic properties to the
compiler or to the run-time, it can exploit alternate representations and
implementations.&lt;/p&gt;
&lt;p&gt;Well-known algebraic properties translate to useful hints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Associative&lt;/em&gt;: grouping doesn't matter&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Commutative&lt;/em&gt;: order doesn't matter&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Idempotent&lt;/em&gt;: duplicates don't matter&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Identity&lt;/em&gt;: the current value doesn't matter&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Zero&lt;/em&gt;: other values don't 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 order.&lt;/p&gt;
&lt;h1&gt;Automatic parallelism in 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 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 cluster.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/facebook/Haxl"&gt;Facebook's Haxl library&lt;/a&gt; can automatically
execute independent data fetching operations concurrently.  Haxl, with the
compiler'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's
presentation&lt;/a&gt; is a great
introduction of the ideas behind this 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's essence, is
burdened with managing loops, states and the details of a sequential-looking
runtime 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
efficient.&lt;/p&gt;
&lt;p&gt;The inspiration to this article came from the talk "Four Solution to a Trivial
Problem" 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's post on &lt;a href="https://bartoszmilewski.com/2010/05/11/parallel-programming-with-hints/"&gt;Parallel Programming with
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 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 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 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 it.&lt;/p&gt;
&lt;h1&gt;Concept zoo&lt;/h1&gt;
&lt;p&gt;I reviewed five popular CI/CD systems where users model their software delivery
process by defining a 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 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 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's see how the relevant user documentation describe the pipeline and its
related concepts.&lt;/p&gt;
&lt;h2&gt;Task, action, step&lt;/h2&gt;
&lt;p&gt;The reviewed systems call the pipeline's unit of work task, action or step.&lt;/p&gt;
&lt;p&gt;Azure 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 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 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 fail.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitHub 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 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
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 command.&lt;/p&gt;
&lt;p&gt;Concourse's task definition proposes a precise semantic model: a task is a
function.  We will build on this model later.&lt;/p&gt;
&lt;h2&gt;Job&lt;/h2&gt;
&lt;p&gt;A job is an ensemble of tasks, actions or steps.&lt;/p&gt;
&lt;p&gt;Azure 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 agent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CircleCI&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Jobs are collections of 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 execute.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitHub 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 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 order.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At this concept the definitions start to diverge, still there are some common
points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Actions, tasks or steps build up jobs.&lt;/li&gt;
&lt;li&gt;A job's components usually run sequentially.&lt;/li&gt;
&lt;li&gt;A job's components usually run on the same build agent, executor or
  runner.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The notable exceptions are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In Concourse it's possible to run a job'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's
  tasks are 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 stage.&lt;/p&gt;
&lt;p&gt;Azure 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 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
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 concurrently.&lt;/p&gt;
&lt;p&gt;CircleCI, Concourse and GitHub Actions don't have this concept.&lt;/p&gt;
&lt;h2&gt;Pipeline, workflow&lt;/h2&gt;
&lt;p&gt;We now are ready to define a pipeline, also called workflow.&lt;/p&gt;
&lt;p&gt;Azure Pipelines&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A pipeline defines the continuous integration and deployment process for your
app.  It's made up of one or more 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 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
flow.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitHub 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 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 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 dependencies.&lt;/p&gt;
&lt;h1&gt;Pipeline, simplified&lt;/h1&gt;
&lt;p&gt;Now we've seen &lt;em&gt;some&lt;/em&gt; of the concepts of the most popular CI/CD systems.  Some
systems have even more which I didn't cover here.&lt;/p&gt;
&lt;p&gt;Do we need all these to model the software deliver process?&lt;/p&gt;
&lt;h2&gt;Task as a function&lt;/h2&gt;
&lt;p&gt;Let's revisit Concourse's task definition: &lt;em&gt;A task can be thought of as a
function from inputs to outputs that can either succeed or 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
what.&lt;/p&gt;
&lt;p&gt;Let's see some task 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 output.&lt;/li&gt;
&lt;li&gt;A test task takes the compiled binary as input and produces a test report as
  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 OK) it releases the
  binary and returns a link to repository where the software can be downloaded.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I named the unit of work "task".  As we've seen other systems prefer "step" or
"action", which would be totally fine as well.&lt;/p&gt;
&lt;p&gt;Let's write down formally Concourse's task 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 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 Haskell's &lt;code&gt;Maybe&lt;/code&gt; type.  In other languages this is 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's syntax but this is not important.
What matters is that our model, the Task's meaning, is mathematical function.&lt;/p&gt;
&lt;p&gt;These are the type signatures of the tasks described previously in 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 code.&lt;/p&gt;
&lt;h2&gt;Sequential composition&lt;/h2&gt;
&lt;p&gt;Let's define a task to tests the incoming pull requests of our project.&lt;/p&gt;
&lt;p&gt;This task takes the pull request'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 change.&lt;/p&gt;
&lt;p&gt;In short, we want sequence the tasks &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;.  If we had an operator
with this type 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 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 a &lt;code&gt;Task&lt;/code&gt; because it's a function with the right
  type signature&lt;/li&gt;
&lt;li&gt;The source code is fed to the first task, &lt;code&gt;build&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The resulting type 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 failure&lt;/li&gt;
&lt;li&gt;Otherwise, feed the compiled binary to &lt;code&gt;test&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I haven't shown you the definition of &lt;code&gt;inSequence&lt;/code&gt;, but you can verify that in
the expression &lt;code&gt;validatePullRequests&lt;/code&gt; the types match.  You can also see that
&lt;code&gt;inSequence&lt;/code&gt; looks almost like regular function composition except the output
types are wrapped in &lt;code&gt;Maybe&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Parallel composition&lt;/h2&gt;
&lt;p&gt;Let's consider now two independent 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 the &lt;code&gt;SourceCode&lt;/code&gt; value.&lt;/p&gt;
&lt;p&gt;We don't want to introduce a new concept, but we want the result of parallel
composition to be a &lt;code&gt;Task&lt;/code&gt; as well.  We're after an operator with the following
type 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 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 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 "fan-out" structure in the pipeline
where independent transformation steps are applied on the same input.&lt;/p&gt;
&lt;h1&gt;Semantic model&lt;/h1&gt;
&lt;p&gt;In the previous sections we've defined a denotational model for CI/CD build
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 rules.&lt;/p&gt;
&lt;p&gt;I've shown you &lt;code&gt;inSequence&lt;/code&gt; and &lt;code&gt;inParallel&lt;/code&gt; combinators. For reference,
without explanation, here are their 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's semantic model without
operational terms or unnecessary limiting assumptions.&lt;/p&gt;
&lt;p&gt;It turns out 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 process.&lt;/p&gt;
&lt;p&gt;Using this model, jobs, stages, workflows and pipelines are just &lt;code&gt;Task&lt;/code&gt;s.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Today's popular CI/CD systems are built around the metaphor and not a rigorous
definition of a pipeline.  I 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 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 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; CI team for the
inspirational discussions during coffee breaks.&lt;/p&gt;
&lt;p&gt;I'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 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 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 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 importance.&lt;/p&gt;
&lt;p&gt;Pure functions express intent explicitly because, by definition, they don'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'm dropping the "pure" 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 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 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 example.&lt;/p&gt;
&lt;p&gt;Consider the following, INI-style, configuration 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'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's address is different in these two environments.&lt;/p&gt;
&lt;p&gt;This is pretty standard, we see similar configuration blocks everywhere.
Where's the functional programming here?&lt;/p&gt;
&lt;p&gt;With the configuration blocks we implicitly created a simple function.  Its
imaginary type signature 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 URL.
If we saw such a function signature in an application, we could implement it
like 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's familiar syntax, but this is not 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't see this function written
out, but it's hidden somewhere between the configuration format parser library
and our application's 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's configuration.&lt;/p&gt;
&lt;h1&gt;But the configuration is simple&lt;/h1&gt;
&lt;p&gt;Let's continue on the previous example and add more configuration 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'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's database-as-service offering called Relational Database Service (RDS).&lt;/p&gt;
&lt;p&gt;Note that I reused the value of &lt;code&gt;db_backend&lt;/code&gt; in the definition 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'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 ask:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is a valid section name?&lt;/li&gt;
&lt;li&gt;What happens if I repeat the same entry in a section?&lt;/li&gt;
&lt;li&gt;What happens if I omit an entry in a section?&lt;/li&gt;
&lt;li&gt;What are the interpolation rules of the percent 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 'configuration block' looks deceptively simple. It
takes quite some effort to precisely explain what a file like this means.&lt;/p&gt;
&lt;p&gt;Now let's see how this configuration file looks if we represent it explicitly
as a 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 INI syntax?  Well, not necessarily, but it triggers
different kinds of thoughts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Should we avoid repeating 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 configuration?&lt;/li&gt;
&lt;li&gt;Should we split the database configuration in a separate 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't configuration deserve
the same level of scrutiny?&lt;/p&gt;
&lt;p&gt;Again, I gave the example in Python's syntax for simplicity, but the
configuration language doesn't have to be Python, but it could support function
definitions.&lt;/p&gt;
&lt;h1&gt;Functions hide everywhere&lt;/h1&gt;
&lt;p&gt;Let's leave our toy example and look for functions 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 line.&lt;/p&gt;
&lt;p&gt;The appearance of the word 'variable' 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; too.&lt;/p&gt;
&lt;p&gt;Now Packer is a wonderful tool and I'm not claiming that there's anything wrong
with it.  I just want you to realize that in a Packer configuration there lies
an ad hoc, mini functional 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's just a pity because variable scoping is pretty well understood since the
development of ALGOL in the 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 it.&lt;/p&gt;
&lt;p&gt;Terraform'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;"module"&lt;/a&gt;.  Just
observe the language used to describe them.  These are quotes from the
documentation, the emphasis is mine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Input variables&lt;/em&gt; to accept values from the calling module.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Output values&lt;/em&gt; to return results to the calling 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's no surprise that modules actually are functions, or they should 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 the &lt;code&gt;import&lt;/code&gt; keyword.&lt;/p&gt;
&lt;h2&gt;Ansible and 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' configuration in a YAML file and these
systems make sure that the desired files, software, etc., are deployed on 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's assigned IP address).  These templates are functions which take
user parameters as arguments and return the rendered configuration file as a
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't be surprised to find word "variable" again.  The &lt;a href="https://docs.ansible.com/ansible/latest/index.html"&gt;second
paragraph&lt;/a&gt; of Ansible's documentation claims: &lt;em&gt;Ansible's main
goals are simplicity and ease of use&lt;/em&gt;.  Take a look how "simple" 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 names&lt;/h1&gt;
&lt;p&gt;What's wrong with the names "template", "role" and "formula"?  Just replace all
their occurrences with the word "function" and we're done.  Well, no.  It's not
at all about 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're manipulating functions in your software configuration you're throwing
away 60+ years worth of computer science.  Additionally, you'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 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 systems.&lt;/p&gt;
&lt;p&gt;Of course this not to say &lt;em&gt;just use Maths and you're done&lt;/em&gt;.  There's a lot more
to a good configuration language than that.  Nevertheless, I firmly believe
that it's possible to provide developer ergonomics, readability on top of solid
concepts borrowed from Mathematics and Computer 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't appear explicitly but disguised.
This leads to the proliferation of ill-defined concepts and idiosyncratic 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 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 general.&lt;/p&gt;
&lt;h1&gt;Acknowledgment&lt;/h1&gt;
&lt;p&gt;I'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 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'Reilly Veocity conference in Berlin.  This post
documents the sessions I liked the 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'Reilly Velocity&lt;/a&gt; conference.
This post documents the sessions I liked the 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
tutorials.&lt;/p&gt;
&lt;h2&gt;Open Telemetry 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 applications.&lt;/p&gt;
&lt;p&gt;Our task was to instrument the provided Go code.  This was an HTTP service
computing the Fibonacci sequence using its recursive definition.  To compute
the preceding two numbers in the sequence the server code repeatedly issues
HTTP client calls to itself.  This implementation is terrible for production,
but it is an excellent classroom 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 computer.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opentelemetry.io/docs/"&gt;OpenTelemetry documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://godoc.org/go.opentelemetry.io/otel"&gt;Go documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;SRE classroom (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 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 (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's homepage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;90% of the problems are solved with just 40 basic principles&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/TRIZ"&gt;TRIZ - theory of inventive problem 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 (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 (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't that good
  finally) Björn Rabenstein (Grafana 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 (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 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 (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 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 (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's 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 (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 "DIE" triad: distributed, immutable, and ephemeral infrastructure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Cultivating production excellence&lt;/em&gt; Liz Fong-Jones (Honeycomb)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Keptn: Don't let your deliver pipelines become your next legacy code&lt;/em&gt;
(Dynatrace 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 (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 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 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 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 paper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Consensus_(computer_science)"&gt;Consensus on 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 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 PR with &lt;a href="https://github.com/lehins"&gt;Alexey
Kuleshevich&lt;/a&gt;, the project's maintainer, he suggested
some improvements.  In this post I describe a simplified version of the
resulting upstream pull-request and explain how it works.&lt;/p&gt;
&lt;h1&gt;Retrying in case of 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 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 (CI) 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 CI 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
again...&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 user.&lt;/p&gt;
&lt;h1&gt;Give me an 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 HTTP request is retried&lt;/a&gt;, in this post I'm using a
simpler example.  The action we will retry is a question: we ask the user for an
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 returns &lt;code&gt;Nothing&lt;/code&gt; if the user enters anything but an 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 function &lt;code&gt;retry&lt;/code&gt; with the
following type 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 "baked-in".
In other words the &lt;code&gt;retry&lt;/code&gt; alters the action's runtime behavior, but it doesn't
change its type.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;retry&lt;/code&gt; will operate like 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's was finally received.&lt;/p&gt;
&lt;h1&gt;Implementing retry&lt;/h1&gt;
&lt;p&gt;Here's an implementation 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, called &lt;code&gt;go&lt;/code&gt; by convention.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The provided action is executed and its result is passed to &lt;code&gt;go&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The action succeeded, just return its result&lt;/li&gt;
&lt;li&gt;The action failed, try again&lt;/li&gt;
&lt;li&gt;If limit is reached we return &lt;code&gt;Nothing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Otherwise inform the user about the retry in progress&lt;/li&gt;
&lt;li&gt;Re-execute the action&lt;/li&gt;
&lt;li&gt;Pass the result to the next iteration of &lt;code&gt;go&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In real code we'd &lt;a href="https://en.wikipedia.org/wiki/Exponential_backoff"&gt;wait a bit&lt;/a&gt; before step ⑥ , but now I'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 section.&lt;/p&gt;
&lt;p&gt;Notice that &lt;code&gt;retry&lt;/code&gt; is polymorphic in the action's return type &lt;code&gt;a&lt;/code&gt;.  In the
function's body we don't manipulate this value at all, therefore &lt;code&gt;a&lt;/code&gt; can stand
for &lt;em&gt;any&lt;/em&gt; type.&lt;/p&gt;
&lt;p&gt;Let's develop an automatic test for this function and convince ourselves and
our colleagues that this function really does what it's supposed to do.  The
bad news is that in its current shape this function is hard to test because
it's doing too much IO operations.&lt;/p&gt;
&lt;p&gt;Next, we are going to make &lt;code&gt;retry&lt;/code&gt; more polymorphic and more testable.&lt;/p&gt;
&lt;h1&gt;Make it more polymorphic&lt;/h1&gt;
&lt;p&gt;The problem with the first implementation is the appearance of &lt;code&gt;IO&lt;/code&gt;.  We need
to get rid of that.  Notice that in the function's body we don't do &lt;em&gt;abitrary&lt;/em&gt;
IO operation but really just calling &lt;code&gt;putStrLn&lt;/code&gt; as a logging function.  The
appearance of the bind (&lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt;) operator tells us that we exploit that IO is a
monad.&lt;/p&gt;
&lt;p&gt;Inspired by these two observations we replace &lt;code&gt;IO&lt;/code&gt; with a generic &lt;code&gt;m&lt;/code&gt; type
constructor with two 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 ("built-in"). We define the
&lt;code&gt;HasLogFunc&lt;/code&gt; class 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 the &lt;code&gt;HasLogFunc&lt;/code&gt; as an interface where &lt;code&gt;logInfo&lt;/code&gt;
must be implemented.  The last two lines provide &lt;code&gt;IO&lt;/code&gt; with an instance of this
interface: the implementation of &lt;code&gt;logInfo&lt;/code&gt; is 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 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 what &lt;code&gt;m&lt;/code&gt; can be: it must be a monad and must have a
   log function&lt;/li&gt;
&lt;li&gt;Instead of &lt;code&gt;IO&lt;/code&gt;-only, the function operates on generic actions of &lt;code&gt;m&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;We replace &lt;code&gt;putStrLn&lt;/code&gt; with &lt;code&gt;logInfo&lt;/code&gt; which is available 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 because &lt;code&gt;IO&lt;/code&gt; is a
monad and we took care of its &lt;code&gt;HasLogFunc&lt;/code&gt; instance.&lt;/p&gt;
&lt;h1&gt;More polymorphic, more testable&lt;/h1&gt;
&lt;p&gt;This new version of &lt;code&gt;retry&lt;/code&gt; is more testable because in our test code we are
free to use any &lt;code&gt;m&lt;/code&gt; (given it satisfies the constraints we imposed) to express
our assertions.  To demonstrate this let's test if the right sequence of error
messages are displayed to the user.  For example, if we had an action which
always 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'd expect retries until the specified number of attempts is exhausted.&lt;/p&gt;
&lt;p&gt;We want our tests to be pure therefore,  instead of using &lt;code&gt;IO&lt;/code&gt;, we implement 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 type &lt;code&gt;String&lt;/code&gt;.  We
specify what &lt;code&gt;logInfo&lt;/code&gt; means in this 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 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 case &lt;code&gt;Nothing&lt;/code&gt;,
paired up with the log messages which were produced during the evaluation.
&lt;code&gt;FakeAction&lt;/code&gt; is pure, it doesn't do any IO, but it helps us to test &lt;code&gt;retry&lt;/code&gt;'s
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'll see how I implemented
exponential back-off: in 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
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 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'm going to show you 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 …&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'm going to show you 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's arguments may be missing (None, NULL, nil, etc.), the
computation in the function may fail because of an unexpected condition, the
function's input argument may be the result of an asynchronous 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 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'm using examples written in Python and Haskell.&lt;/p&gt;
&lt;h1&gt;Modeling a camera&lt;/h1&gt;
&lt;p&gt;As a working example, let's model a camera with a projection from a
three-dimensional world point coordinates to two-dimensional image point
coordinates.&lt;/p&gt;
&lt;p&gt;In Haskell the type signature of such a function 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 of &lt;code&gt;WorldPoint&lt;/code&gt; and
&lt;code&gt;ImagePoint&lt;/code&gt; exist.  That is, given a world point &lt;code&gt;project&lt;/code&gt; returns a point on
the camera's image plane.&lt;/p&gt;
&lt;p&gt;In Python the outline of this function would 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 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's body.&lt;/p&gt;
&lt;p&gt;Let's see how we could use the &lt;code&gt;project&lt;/code&gt; function in various contexts.&lt;/p&gt;
&lt;h1&gt;Simplest 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 calling &lt;code&gt;project&lt;/code&gt;.  It's easy both in 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 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 simple.&lt;/p&gt;
&lt;h1&gt;Missing value&lt;/h1&gt;
&lt;p&gt;Imagine that a preceding computation provides an empty world point to our
program.  We would like to use &lt;code&gt;project&lt;/code&gt; in this context where the world point
may not be present.&lt;/p&gt;
&lt;p&gt;In Python, the missing value could be represented as a &lt;code&gt;None&lt;/code&gt; value.  Let's use
a conditional to check for 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 base.&lt;/p&gt;
&lt;p&gt;In Haskell we could accept the world point wrapped in a &lt;code&gt;Maybe&lt;/code&gt; type and use
&lt;code&gt;fmap&lt;/code&gt; to compute a projection in case the world point value is 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 are &lt;code&gt;Maybe WorldPoint&lt;/code&gt; and
&lt;code&gt;Maybe ImagePoint&lt;/code&gt;, respectively.&lt;/p&gt;
&lt;p&gt;This works, because &lt;code&gt;Maybe&lt;/code&gt; is a functor.  This means we can use the function
&lt;code&gt;fmap&lt;/code&gt; to lift our pure &lt;code&gt;project&lt;/code&gt; function to operate on potentially missing
values.&lt;/p&gt;
&lt;h1&gt;Handling a 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 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 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 list.&lt;/p&gt;
&lt;p&gt;In Haskell, choosing a simple list representation for Scene, we 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 of &lt;code&gt;imagePoints&lt;/code&gt; is a list of image points.&lt;/p&gt;
&lt;p&gt;This is almost identical to the Python code using &lt;code&gt;map&lt;/code&gt;.  List is a functor,
&lt;code&gt;fmap&lt;/code&gt; on list applies the provided function on each element.  This is exactly
&lt;code&gt;map&lt;/code&gt; as we know it from Python.&lt;/p&gt;
&lt;h1&gt;Input from a data file&lt;/h1&gt;
&lt;p&gt;Let's imagine that the world point is stored on disk in a data file.  Before we
can apply &lt;code&gt;project&lt;/code&gt; we need to read and decode the data file.&lt;/p&gt;
&lt;p&gt;In Python, we wrap the file operation in 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't forget
to write it, allows us to handle the potential errors.&lt;/p&gt;
&lt;p&gt;In Haskell, it's again 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 and &lt;code&gt;fmap&lt;/code&gt; acts as follows: if the
decoding is successful &lt;code&gt;project&lt;/code&gt; is applied on the returned value.  In case of
error the &lt;code&gt;project&lt;/code&gt; function is not used at all and &lt;code&gt;imagePointOrError&lt;/code&gt; will
contain the returned error 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 compile.&lt;/p&gt;
&lt;h1&gt;Asynchronous request&lt;/h1&gt;
&lt;p&gt;Finally let's assume that we read the world point from the network.  Network
communication requires a lot of input/output so let's do it concurrently with
other tasks of our 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 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 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 by
   &lt;code&gt;read_from_network&lt;/code&gt;.  This is also a coroutine and it completes after the
    network communication has 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 value.
   &lt;code&gt;image_point&lt;/code&gt; is now a regular image point value.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now let's see how something similar works in 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 IO: the body of this function can be
   replaced with calls to a real networking library which do not know anything
   about asynchronous operations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Spawn the network operation asynchronously in a separate (lightweight)
   thread.  Note 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 keyword.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We use &lt;code&gt;fmap&lt;/code&gt; to lift the transformation into the asynchronous computation,
   then &lt;code&gt;wait&lt;/code&gt; blocks until the asynchronous action completes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By looking at the type signature of &lt;code&gt;fmap&lt;/code&gt; specialized to this 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 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 the &lt;code&gt;Async&lt;/code&gt; constructor and transforms the underlying 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
actions.&lt;/p&gt;
&lt;p&gt;In Python we used different, specialized language constructs to apply 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 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 points&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Try-except block&lt;/em&gt;: when the data file decoding may 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 computations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Haskell we always 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 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 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 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's features to write concurrent programs.  I developed a simulated
search engine which looked like 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 wins&lt;/h1&gt;
&lt;p&gt;In the heart of the &lt;code&gt;search30&lt;/code&gt; function we find this helper 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.  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 terminated.&lt;/p&gt;
&lt;p&gt;In real code you would replace the &lt;code&gt;fakeSearch&lt;/code&gt; function with an appropriate
search API call but the structure of the function would not change
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's
origin for further analysis.&lt;/p&gt;
&lt;p&gt;This implementation 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's see how we can add
support for any number of back-end servers.&lt;/p&gt;
&lt;h1&gt;More general race&lt;/h1&gt;
&lt;p&gt;Instead of racing two processes, we start &lt;code&gt;N&lt;/code&gt; instances of 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 same.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;race&lt;/code&gt; function served us well, so let'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't take too long to
locate these two 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 use &lt;code&gt;waitAnyCancel&lt;/code&gt; to achieve the same behavior
as &lt;code&gt;race&lt;/code&gt; but for a list of asynchronous operations.&lt;/p&gt;
&lt;p&gt;We cannot just 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 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 fit &lt;code&gt;waitAnyCancel&lt;/code&gt; into &lt;code&gt;fastest&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Building blocks&lt;/h1&gt;
&lt;p&gt;The central type of the async library, &lt;code&gt;Async a&lt;/code&gt;, represents an asynchronous
operation that yields a value of type &lt;code&gt;a&lt;/code&gt;.  Asynchronous operations can be
spawned using 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 expression &lt;code&gt;fakesearch query kind&lt;/code&gt; is &lt;code&gt;IO String&lt;/code&gt;.  Feeding
this to &lt;code&gt;async&lt;/code&gt;, &lt;code&gt;async (fakesearch query kind)&lt;/code&gt;, we get an &lt;code&gt;IO (Async String)&lt;/code&gt;
which launches the search asynchronously in a separate thread.  We could
replicate this &lt;code&gt;N&lt;/code&gt; times and 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's identity.&lt;/p&gt;
&lt;p&gt;When we used &lt;code&gt;race&lt;/code&gt; it was easy to identify the faster replica because we used
pattern matching on the 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 fastest.&lt;/p&gt;
&lt;p&gt;Now, because &lt;code&gt;IO a&lt;/code&gt; is a functor, we can use &lt;code&gt;fmap&lt;/code&gt; (usually abbreviated as
&lt;code&gt;&amp;lt;$&amp;gt;&lt;/code&gt;) to apply a function on the result of the search operation.  Let's write
a function which prepends the server's identity to the search 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 read: &lt;code&gt;servedBy 2 &amp;lt;$&amp;gt; fakeSearch query kind&lt;/code&gt;.  The type of this
expression is still &lt;code&gt;IO String&lt;/code&gt; but it yields the search result with the server
name prepended.&lt;/p&gt;
&lt;p&gt;Let's go over the series of transformation steps and see how the expressions
and their types were 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 step.&lt;/p&gt;
&lt;h1&gt;Final implementation&lt;/h1&gt;
&lt;p&gt;Let's assemble the new &lt;code&gt;fastest&lt;/code&gt; implementation from the pieces we 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;① Use &lt;code&gt;forM&lt;/code&gt; to transform a list of integers, the replica identifiers, by
  applying the provided function. &lt;code&gt;requests&lt;/code&gt; has a type &lt;code&gt;[Async String]&lt;/code&gt;,
  exactly what &lt;code&gt;waitAnyCancel&lt;/code&gt; needs.&lt;/p&gt;
&lt;p&gt;② The second argument of &lt;code&gt;forM&lt;/code&gt; is the transformation function which creates
  an asynchronous operation yielding the search result with the replica's
  identity prepended.&lt;/p&gt;
&lt;p&gt;③ Call &lt;code&gt;waitAnyCancel&lt;/code&gt; and extract the result from the fastest search
  operation (we don't use first element of the returned tuple).&lt;/p&gt;
&lt;p&gt;④ Provide result of the current IO operation.&lt;/p&gt;
&lt;p&gt;This implementation, only six lines of code,  works with any number of
replicas.  For &lt;code&gt;numReplicas=2&lt;/code&gt; its behavior is identical to that of the old
one.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;We replaced the original implementation of 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 replicas.&lt;/p&gt;
&lt;p&gt;The implementation relies on a single library function &lt;code&gt;waitAnyCancel&lt;/code&gt; but we
needed to arrange the asynchronous search operations in a way that is
compatible with &lt;code&gt;waitAnyCancel&lt;/code&gt;'s type signature.  We used generic combinators
such as &lt;code&gt;fmap&lt;/code&gt; and &lt;code&gt;forM&lt;/code&gt; to achieve this.  The &lt;code&gt;search30&lt;/code&gt; requires no
modifications, as the type signature of &lt;code&gt;fastest&lt;/code&gt; didn't 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 as &lt;code&gt;fmap&lt;/code&gt; for implementing our 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'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 "Build systems à la carte" 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.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today I went to the talk "Build systems à la carte" 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 resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://doi.org/10.1145/3236774"&gt;paper submitted to ICFP 2018&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=BQVT6wiwCxM"&gt;presentation from ICFP 2018&lt;/a&gt; by
  Simon Peyton-Jones (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
  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's
  presentation&lt;/a&gt;
  (the talk was not recorded)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/snowleopard/build"&gt;code examples on 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 EPFL, Lausanne.  In the next sections
I summarize what I learned from the paper and the presentation.&lt;/p&gt;
&lt;h1&gt;Build 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 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'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 properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Minimality&lt;/em&gt;: don't repeat work unnecessarily&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Early cutoff&lt;/em&gt;: stop when nothing changes&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Cloud builds&lt;/em&gt;: save repeating work by sharing build results among all 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 build.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Classification space&lt;/h1&gt;
&lt;p&gt;Two key design choices are typically deeply wired in any build system:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Scheduling&lt;/em&gt;: the order in which tasks are built&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Rebuilding&lt;/em&gt;: whether or not a task is rebuilt&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Today's most commonly used build systems can be classified along these two
axes.  Let's see these two aspects in detail.&lt;/p&gt;
&lt;h2&gt;Scheduling strategies&lt;/h2&gt;
&lt;p&gt;Build systems use different strategies to execute the build 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, 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, 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, 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 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 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 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 tasks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Rebuilding strategies&lt;/h2&gt;
&lt;p&gt;We find the following techniques to decide whether or not a task is 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, 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, 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. (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, Nix)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Again, picking a given rebuilding strategy has interesting consequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can achieve minimality using dirty bits.&lt;/li&gt;
&lt;li&gt;It's possible but hard to support early cutoff with dirty bits.  Make
  approximates early cut-off.&lt;/li&gt;
&lt;li&gt;All traces support dynamic dependencies and minimality&lt;/li&gt;
&lt;li&gt;All traces except for deep traces support the early cutoff optimization&lt;/li&gt;
&lt;li&gt;Constructive traces enable cloud builds&lt;/li&gt;
&lt;li&gt;Deep constructive traces cannot support early cutoff&lt;/li&gt;
&lt;li&gt;Deep constructive traces may generate frankenbuilds if the tasks are not
  deterministic&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Executable build system 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 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'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 "Build systems à la carte" 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 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 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 Haskell.&lt;/p&gt;
&lt;h1&gt;Parser 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(CSV)&lt;/a&gt; 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 CSV 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 the &lt;code&gt;csvFile&lt;/code&gt; example I didn't find any of those:  I
can &lt;em&gt;see&lt;/em&gt; that the code describes the CSV file, but where is all the parsing
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 English:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A CSV file is zero or more occurrences of lines, separated and ended by
  end-of-line&lt;/li&gt;
&lt;li&gt;A line is zero or more occurrences of cells, separated by comma&lt;/li&gt;
&lt;li&gt;A cell is either a quoted cell or zero or more characters, excluding comma
  and 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 the &lt;code&gt;line&lt;/code&gt;, &lt;code&gt;cell&lt;/code&gt; and
the &lt;code&gt;quotedCell&lt;/code&gt; parsers can be developed, tested and maintained 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 ANTLR 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's no need for preprocessing or external
tooling. In Haskell you can even try your parsers in an interactive REPL
session.  These features make it cheap to write ad-hoc parsers in your
programs.&lt;/p&gt;
&lt;h1&gt;Haskell 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 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 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;"nice balance between speed,
flexibility, and quality of parse errors"&lt;/em&gt;.  Sounds good to me.  I decided to
give Megaparsec a 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;README of megaparsec&lt;/a&gt; contains a more detailed comparison
with other solutions.&lt;/p&gt;
&lt;h1&gt;Using Megaparsec&lt;/h1&gt;
&lt;p&gt;In spite of  Megaparsec'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 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 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 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 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 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;
parser.&lt;/p&gt;
&lt;p&gt;Solving a typical parsing problem, such as parsing a CSV-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 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 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'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'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 …&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'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'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 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 "computing unit" simply
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 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 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 result.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Balancer&lt;/em&gt;: Receives requests and distributes them among the available 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 Requester.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The components communicate through channels.  I shall use unbounded FIFO
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
requester.&lt;/p&gt;
&lt;h1&gt;Request&lt;/h1&gt;
&lt;p&gt;First, let's define the data structure to hold the requests.  This is a type of
a request that, when executed, yields a value of 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 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 "fit" in the result channel.&lt;/p&gt;
&lt;h1&gt;The task and the Requester&lt;/h1&gt;
&lt;p&gt;Let's start imagining how the clients would interact with the load balancer.
We generate some work with &lt;code&gt;randomTask&lt;/code&gt;, a function with the 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 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 of &lt;code&gt;randomTask&lt;/code&gt; is the time it took to
complete it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;requester&lt;/code&gt; function represent the clients who have some work to 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 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;.  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 the &lt;code&gt;Request&lt;/code&gt; on the other end of the channel.&lt;/p&gt;
&lt;h1&gt;Balancer&lt;/h1&gt;
&lt;p&gt;As shown in the design, the &lt;code&gt;Balancer&lt;/code&gt; receives the &lt;code&gt;Request&lt;/code&gt; from a channel
and distributes them among the available workers.&lt;/p&gt;
&lt;p&gt;The Balancer holds a pool of workers and a completion 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 the &lt;code&gt;Balancer&lt;/code&gt; the completion
of a task.  The &lt;code&gt;Balancer&lt;/code&gt; uses this information to keep track of the load of
each 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's walk through
it step by 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.  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 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 function &lt;code&gt;work ::
   Worker a -&amp;gt; TChan (Worker a) -&amp;gt; IO ()&lt;/code&gt; is part of the Worker API and makes
   the worker process requests in an infinite loop.  I shall present the
   details of the &lt;code&gt;Worker&lt;/code&gt; in the next section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The balancer waits for new messages on the request and completion channels.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Depending on the received message &lt;code&gt;runBalancer&lt;/code&gt; calls 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 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 pool.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;RequestReceived&lt;/code&gt; and the &lt;code&gt;WorkerDone&lt;/code&gt; are data constructors of an internal
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 "tags" the incoming message so we can differentiate from where it was originated.&lt;/p&gt;
&lt;p&gt;The communication channels of 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;
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 pairs &lt;code&gt;(Int, Worker a)&lt;/code&gt;.  The priority
represents the number of tasks assigned to the worker.  Because we are using
&lt;code&gt;MinPrioHeap&lt;/code&gt; the pair with minimal priority, that corresponding to the least
loaded worker, is extracted first.&lt;/p&gt;
&lt;p&gt;The two functions &lt;code&gt;dispatch&lt;/code&gt; and &lt;code&gt;complete&lt;/code&gt;, introduced in the definition of
&lt;code&gt;balance&lt;/code&gt;, manipulate the heap of the worker pool.  The function &lt;code&gt;dispatch&lt;/code&gt;
selects the least loaded worker and schedules the request on 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 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 tasks.&lt;/li&gt;
&lt;li&gt;The function &lt;code&gt;schedule :: Worker a -&amp;gt; Request a -&amp;gt; IO ()&lt;/code&gt; is part of the
   Worker API and it sends the given request to the extracted 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 pool.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;completed&lt;/code&gt; function is very similar 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 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
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's main 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 channels.&lt;/p&gt;
&lt;p&gt;For better encapsulation I provide a short helper function to send a request to
the 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 function &lt;code&gt;schedule&lt;/code&gt; deconstructs the &lt;code&gt;Worker&lt;/code&gt; and sends the provided
request to its internal channel.  This function allows &lt;code&gt;Worker&lt;/code&gt; to remain
opaque and the request channel is not exposed outside the worker's module.&lt;/p&gt;
&lt;h1&gt;Putting it all 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 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 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 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 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 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'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's the …&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'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's the button for my latest vague idea? Or where should I
click to record an abstract concept?&lt;/p&gt;
&lt;p&gt;As an experiment, let's say you're learning Math.  Try recording digitally
Pythagoras's famous formula using the device you're reading this post 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'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'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're working through
all 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 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'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't considered before!  In less then five minutes the
sixth version of your graph must be something solid.  Maybe not perfect, but
it'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'm
usually browsing on a support forum trying to figure out how to do a certain
operation.  If I'm lucky I get fancy bar chart in half an hour.  I don't like
it, but I'm already &lt;em&gt;out of ideas&lt;/em&gt; how to make it 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
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 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'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 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 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 programming.&lt;/p&gt;
&lt;h1&gt;The 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 for &lt;span class="math"&gt;\(N\)&lt;/span&gt; cents, and we have infinite supply of each 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 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 options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;we use the &lt;span class="math"&gt;\(S_m\)&lt;/span&gt; valued coin in the change and we try to find the change
   for &lt;span class="math"&gt;\(N - S_m\)&lt;/span&gt; cents with the same set of coins.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;we decide not to use the &lt;span class="math"&gt;\(S_m\)&lt;/span&gt; valued coin in the change: we keep on looking
   for a change of &lt;span class="math"&gt;\(N\)&lt;/span&gt; cents 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 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 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 the &lt;span class="math"&gt;\(\min\)&lt;/span&gt; function correspond to the two options described
above.  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 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 of &lt;span class="math"&gt;\(C(N,m)\)&lt;/span&gt; is 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 for &lt;span class="math"&gt;\(N\)&lt;/span&gt; with the given coins.  The case (1) applies when we successfully
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
change.&lt;/p&gt;
&lt;p&gt;For simplicity, we will use a fixed set of 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 by &lt;span class="math"&gt;\(C(40, 4)\)&lt;/span&gt;.  Also note that we only compute the number of
coins, we don't give the exact denominators to be used in the 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 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 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 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 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 problem.&lt;/p&gt;
&lt;p&gt;Since there are cases where the change is impossible, we choose the result 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 possible.&lt;/p&gt;
&lt;p&gt;With this preparation we are ready to implement the first version of &lt;code&gt;change&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;Naive 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
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 result &lt;code&gt;Change&lt;/code&gt; forces us to deviate from the
clean mathematical formulation at two places:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;we use &lt;code&gt;fmap&lt;/code&gt; to add &lt;code&gt;1&lt;/code&gt; to the result of the &lt;code&gt;left&lt;/code&gt; subproblem&lt;/li&gt;
&lt;li&gt;we use our own &lt;code&gt;minOf&lt;/code&gt; function instead of the 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 an &lt;code&gt;Int&lt;/code&gt; to a &lt;code&gt;Maybe Int&lt;/code&gt; because their
types don't match.  Since &lt;code&gt;Maybe Int&lt;/code&gt; is a functor so we can use &lt;code&gt;fmap&lt;/code&gt; to lift
the addition into the context of &lt;code&gt;Maybe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As for the second point, let's see the implementation 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 two &lt;code&gt;Change&lt;/code&gt; values:  if 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 using &lt;code&gt;&amp;lt;|&amp;gt;&lt;/code&gt;.  This behaves similarly to logical OR.  We can easily test
this 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 of &lt;code&gt;minOf&lt;/code&gt; gives us the right behavior when we select the
smaller between the results of the &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt; subproblems.&lt;/p&gt;
&lt;p&gt;The built-in &lt;code&gt;min&lt;/code&gt; can actually operate on &lt;code&gt;Maybe Int&lt;/code&gt; values.  We just cannot
use it here because it returns &lt;code&gt;Nothing&lt;/code&gt; if &lt;em&gt;any&lt;/em&gt; of its argument is &lt;code&gt;Nothing&lt;/code&gt;.
This would terminate our recursive function without exploring the whole
solution 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's see how our solution performs.&lt;/p&gt;
&lt;h1&gt;Performance of the naive 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 naive &lt;code&gt;change&lt;/code&gt; implementation.  Let'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 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's try to improve this!&lt;/p&gt;
&lt;h1&gt;Implementation using dynamic 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
solution.&lt;/p&gt;
&lt;p&gt;We write a new 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 a &lt;code&gt;Change&lt;/code&gt;
value.  We call this 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 write &lt;code&gt;changeD&lt;/code&gt; which, returns a &lt;code&gt;Dyn&lt;/code&gt; computation resulting
in 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're operating in
the &lt;code&gt;Dyn&lt;/code&gt; context, we are using the &lt;code&gt;do&lt;/code&gt; notation.  The &lt;code&gt;memorize&lt;/code&gt; computation
implements the storing and recalling the subproblems' 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 state.&lt;/p&gt;
&lt;p&gt;The final step is to provide &lt;code&gt;change&lt;/code&gt; in a form identical to the naive
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 the &lt;code&gt;Dyn&lt;/code&gt; computation 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's
which of the two implementations is worth using.&lt;/p&gt;
&lt;h1&gt;Naive vs 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 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't come for free: we traded running speed
for storage 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 a &lt;code&gt;Dyn&lt;/code&gt; computation where the solutions
to already solved subproblems are stored in a 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 ... details...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 ... details...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't help.  I just simply
didn't &lt;em&gt;know&lt;/em&gt; any.&lt;/p&gt;
&lt;p&gt;I didn't have a formal training on algorithms and complexity.  Yes, I can
easily write an &lt;span class="math"&gt;\(\mathcal{O}(n^2)\)&lt;/span&gt; sorting algorithm.  Probably I can even make
it &lt;span class="math"&gt;\(\mathcal{O}(n \log n)\)&lt;/span&gt;, but I wouldn't enjoy it.  Of course, I quickly
learned that I shouldn'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 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 "built-in" 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 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're 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't.  For example, in the
talk &lt;a href="https://www.youtube.com/watch?v=eidEEmGLQcU"&gt;STL Algorithms in Action from CppCon 2015&lt;/a&gt; Michael VanLoon solves
interesting sorting problems using components from the &lt;code&gt;&amp;lt;algorithm&amp;gt;&lt;/code&gt; library.
None of those solutions are 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't have this expertise, but
I still want to help my colleagues to solve their domain specific 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'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 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'd say you should also learn a new
algorithm every month.  So next time when you'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 fit...&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'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'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 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this post I'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'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'm interested in learning.&lt;/p&gt;
&lt;h1&gt;Simulating a search engine&lt;/h1&gt;
&lt;p&gt;The example we are going to play with (again, taken from Pike's presentation)
is a simulated search engine.  The search engine receives a search query and
returns web, image and video 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 engine.&lt;/p&gt;
&lt;p&gt;First we're going to need some imports and some data types to represent our 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 along.&lt;/p&gt;
&lt;p&gt;This is already enough to get us started.  We can write a fake search function
which takes a &lt;code&gt;SearchQuery&lt;/code&gt;, a &lt;code&gt;SearchKind&lt;/code&gt; and returns an IO action which, when
run, yields the search result as a 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't get any more sophisticated than this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;we make the current thread sleep for a random number amount of milliseconds, then&lt;/li&gt;
&lt;li&gt;we return the simulated search 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
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 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
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
examples.&lt;/p&gt;
&lt;h1&gt;Search 1.0&lt;/h1&gt;
&lt;p&gt;The first version of our search engine will perform the image, web and video
searches 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 use &lt;code&gt;mapM&lt;/code&gt; to sequentially perform the three kinds of searches.  The result
of a typical search using &lt;code&gt;haskell&lt;/code&gt; as a query would look 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't be about concurrency if we were
to stop here.&lt;/p&gt;
&lt;h1&gt;Search 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 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
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'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 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'd better display an error message if we cannot display a
results within a given amount of 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 "timed out"
message and we send our sincerest apologies to our 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 a &lt;code&gt;timeout&lt;/code&gt; call.  The signature of this
function 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 80ms &lt;code&gt;printResults&lt;/code&gt; will behave as 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 why &lt;code&gt;printResults&lt;/code&gt; takes a &lt;code&gt;Maybe [String]&lt;/code&gt; as 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 printed.&lt;/p&gt;
&lt;h1&gt;Search 3.0&lt;/h1&gt;
&lt;p&gt;We can still do better.  The occasional timeout messages are still annoying.
We won't be too popular if our search website times out too often.  It'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 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 other.&lt;/p&gt;
&lt;p&gt;We write a function &lt;code&gt;fastest&lt;/code&gt; that does exactly 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 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.  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; 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 IO 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 from.&lt;/p&gt;
&lt;p&gt;We now replace the &lt;code&gt;fakeSearch&lt;/code&gt; call with &lt;code&gt;fastest&lt;/code&gt; and we 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's see some typical 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 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 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 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 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'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 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'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, GTD also taught me what I should &lt;em&gt;not&lt;/em&gt; do, and when things …&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'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, GTD 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 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 task?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Is this item is really actionable?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Was there any progress on this project recently?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When these questions arise, it'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 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'd already recognized some points to improve in my working habits during my PhD, but I've been trying to shape my working environment more consciously since I started working in industry.&lt;/p&gt;
&lt;p&gt;Here are some tools I use, techniques I implemented during the last years to support a good GTD work flow.  Most of the my work happens before the computer, so some of the points following are rather specific.&lt;/p&gt;
&lt;p&gt;So here are my tips (for myself and you):&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Avoid distractions&lt;/li&gt;
&lt;li&gt;Be asynchronous&lt;/li&gt;
&lt;li&gt;Be responsive&lt;/li&gt;
&lt;li&gt;Be distributed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's see each point in detail.&lt;/p&gt;
&lt;div class="section" id="avoid-distractions"&gt;
&lt;h2&gt;Avoid distractions&lt;/h2&gt;
&lt;p&gt;As stated earlier this is the most important point.  Distractions destroy productivity.&lt;/p&gt;
&lt;div class="section" id="solid-black-desktop"&gt;
&lt;h3&gt;Solid black 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're good for nothing but distractions.  My desktop has solid black color, no icons or anything at all.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="tiling-is-great"&gt;
&lt;h3&gt;Tiling is great&lt;/h3&gt;
&lt;p&gt;I'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'm working on.  My task bar is very small and only shows the most essential information.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="at-most-two-screens"&gt;
&lt;h3&gt;At most two screens&lt;/h3&gt;
&lt;p&gt;These days it'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 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's basically the same thing as having an annoying &amp;quot;You've got mail&amp;quot; notification on the desktop. Very 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 keep:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;code and documentation,&lt;/li&gt;
&lt;li&gt;code and testing/debugging outputs,&lt;/li&gt;
&lt;li&gt;browser and mail 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't feel limited by its relatively small, 12.5&amp;quot; screen.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="be-asynchronous"&gt;
&lt;h2&gt;Be 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 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 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'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 instead...&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's needed.  In fact, this way the phone call effectively turns into a meeting.  More on meetings in the next 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'll return to this point too later.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="prefer-documentation-to-meetings"&gt;
&lt;h3&gt;Prefer documentation to meetings&lt;/h3&gt;
&lt;p&gt;Just Google the terms &amp;quot;why meetings are bad&amp;quot; or &amp;quot;how to have good meetings&amp;quot; and you'll see my point.  The bottom line is that meetings are super expensive and very 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 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'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 process.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="be-responsive"&gt;
&lt;h2&gt;Be 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'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 mine.&lt;/p&gt;
&lt;p&gt;I try to answer my e-mails in a 'reasonable' time.  It depends on the context what this means:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;work related mails I try to answer within a day.&lt;/li&gt;
&lt;li&gt;a mail from a friend a subject 'how is it going' will be answered in a couple of 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's because I didn't take the time to do it (which effectively means, because I was lazy) not because it was lost or forgotten.  I use the 'Inbox Zero' strategy (the term coined by Merlin Mann) to handle my mails using a super simple system named 'Trusted Trio' 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 distributed&lt;/h2&gt;
&lt;p&gt;Stuff gets done at physically different locations.  For me these locations are: work, home and when I'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 GTD terms: my reference material needs to be accessible from different contexts.&lt;/p&gt;
&lt;p&gt;More specifically:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;It's a commonplace, but I can access my e-mails from 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 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 stations.&lt;/li&gt;
&lt;li&gt;My notes are in a text file in a Dropbox 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'd like to improve on my current setup to make my personal data, such as pictures, documents, etc. more accessible when I'm not home (only for myself in a secure manner
of course).  Maybe I write a post about this some other 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 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 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 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 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 CHF and, according to the reviews, this is the best Android client you can 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 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 SSH key pair to be used by my phone to access the remote Git repositories.  The rest of the infrastructure was already in 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 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 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 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;quot;Project Starfinder&amp;quot;.  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 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 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 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'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 somewhere.&lt;/p&gt;
&lt;p&gt;Anyhow, the messages arrived from the socket and they were processed in a large 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't care about lines longer than 80 characters back 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 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 stuff.&lt;/p&gt;
&lt;p&gt;The motor daemon also had the following features:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;read and parsed a configuration file&lt;/li&gt;
&lt;li&gt;supported arbitrary numbers of motors. In fact the motor objects were stored in a linked list.&lt;/li&gt;
&lt;li&gt;wrote log messages to the syslog&lt;/li&gt;
&lt;li&gt;changes in the motor position were made available to all clients&lt;/li&gt;
&lt;li&gt;handled SIGTERM and SIGCHILD signals and made a clean exit&lt;/li&gt;
&lt;li&gt;it was GPL licensed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I didn'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 :-).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="graphical-client"&gt;
&lt;h2&gt;Graphical 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 GTK interface (with GTK 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 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 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's a pity though that the code didn't move any telescopes...&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 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'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 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;quot; 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
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 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.  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 made.&lt;/p&gt;
&lt;div class="section" id="start-a-new-topical-branch"&gt;
&lt;h2&gt;Start a new topical 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'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 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 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 commits&lt;/h2&gt;
&lt;p&gt;I want to &amp;quot;compress&amp;quot; all these into one single commit, since there's no point having commits in the &lt;tt class="docutils literal"&gt;master&lt;/tt&gt; branch with messages such as &amp;quot;Add summary&amp;quot;, &amp;quot;Fix typo.&amp;quot;, &amp;quot;Continue this and that.&amp;quot;.  In git's words this is called interactive 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;$EDITOR&lt;/tt&gt; with a file to edit the rebase 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 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 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 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 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 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'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's branches and 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's about software development in the wild where clean commits and keeping track of changes you make on the codebase are 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 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 potentiometer.&lt;/p&gt;
&lt;div class="section" id="stepper-motor"&gt;
&lt;h2&gt;Stepper 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 ULN2803A containing 8 Darlington Arrays, takes care of 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 MCP3002 ADC 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! 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 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' wiring, then I wrote a small
test script to provide the correct sequence on the GPIO 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
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 step.&lt;/p&gt;
&lt;p&gt;The 6 wires of this motor (Japan Servo KP68P2-406, 12V, 33 Ω/phase, 1.8
deg/step) are the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;2 red (center taps)&lt;/li&gt;
&lt;li&gt;orange (phase 1)&lt;/li&gt;
&lt;li&gt;brown (phase 2)&lt;/li&gt;
&lt;li&gt;yellow (phase 3)&lt;/li&gt;
&lt;li&gt;black (phase 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 test&lt;/h2&gt;
&lt;p&gt;I wrote a small test script to output the step sequence on the Pi's GPIO
ports.  It has a lot of cool 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 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's GPIO ports through a transistor.  The
LED's could be directly connected to the IO 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 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 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'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 LED and a push-button …&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'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 LED and a push-button from
the Pi.  Despite its apparent simplicity it's a good opportunity re-learn
some basics: which is the anode/cathode of the LED?  What's a
pull-up/pull-down resistor? and so on...&lt;/p&gt;
&lt;p&gt;Here's the final 'product':&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
GPIO ports on the Pi.  I may design a new case in the future, one that allows
direct connection to the 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 LED blinking (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 LED on when the button is 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 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/LED/&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'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 dynamically.&lt;/p&gt;
&lt;p&gt;Also, now there's a Github ribbon in the top right corner …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I changed the blog'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 dynamically.&lt;/p&gt;
&lt;p&gt;Also, now there's a Github ribbon in the top right corner, and social links
on the 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 home.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;At work, I stored all my important data on the lab's server which
(obviously) was backed up once a day.  At home, on my personal laptop I
haven't had a systematic backup solution.  Now I'm changing this.&lt;/p&gt;
&lt;div class="section" id="everyday-backup-with-obnam"&gt;
&lt;h2&gt;Everyday backup with Obnam&lt;/h2&gt;
&lt;p&gt;I decided that I will backup my laptop's important data on my home
file-server.  It's a &lt;a class="reference external" href="http://sharecenter.dlink.com/products/DNS-320"&gt;DNS-320 ShareCenter&lt;/a&gt; with 2x1TB disk in RAID 1.
Naturally, this won'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 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 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 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
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
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't really care loosing.  I also don't backup this way
the &lt;tt class="docutils literal"&gt;pictures&lt;/tt&gt; directory, since I secure my photos in there differently.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="photo-backup-with-git-annex"&gt;
&lt;h2&gt;Photo backup with 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
USB HDD dedicated for this purpose).  A copy of the recent photos, usually
the current year'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 SSD on my laptop is not that spacious, and I don't
want to store all my photos on 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
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't use it,
large part of its (not too high) price goes for charity, I figured.&lt;/p&gt;
&lt;p&gt;I was reluctant to buy a casing for it in the shop, because I …&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't use it,
large part of its (not too high) price goes for charity, I 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;'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 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't do the light-pipes.  I'm not sure if this is the Pi's final casing
and I didn'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 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 PC 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 PC 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
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 CD&lt;/a&gt;.  While setting up the network
(IP address, DNS, etc.), it turns out that the network card needs some
non-free firmware which are not on the Installer/Live CD.  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 USB 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 SSH server 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 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 SSH as
described above.  It takes some time, but the transfer works fine.&lt;/p&gt;
&lt;p&gt;On &lt;tt class="docutils literal"&gt;braindead&lt;/tt&gt;, still running the Live CD,  I mount the new disk 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... 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 MAC address) to the network card which is in the other
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 HTML.  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 HTML.  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
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 RST files
and the neccessary config files for 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 HTML
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 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 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 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 post.&lt;/p&gt;
</content><category term="misc"/><category term="test"/></entry></feed>